什么时候应该在 C# 中使用 as 关键字

发布于 2024-12-06 10:39:44 字数 307 浏览 0 评论 0原文

当你想改变类型时,大多数时候你只想使用传统的演员阵容。

var value = (string)dictionary[key];

它很好,因为:

  • 它很快
  • 如果出现问题它会抱怨(而不是给出 object is null 异常)

那么什么是使用 as 的好例子,我真的找不到或想到完全适合它的东西吗?

注意:实际上,我认为有时编译器会阻止在 as 起作用的情况下使用强制转换(与泛型相关?)。

When you want to change types most of the time you just want to use the traditional cast.

var value = (string)dictionary[key];

It's good because:

  • It’s fast
  • It’ll complain if something is wrong (instead of giving object is null exceptions)

So what is a good example for the use of as I couldn't really find or think of something that suits it perfectly?

Note: Actually I think sometimes there are cases where the complier prevents the use of a cast where as works (generics related?).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

鹿港巷口少年归 2024-12-13 10:39:44

当对象有效时使用as,该对象不是您想要的类型,但如果是您想要的类型,您希望采取不同的操作。例如,在某种伪代码中:

foreach (Control control in foo)
{
    // Do something with every control...

    ContainerControl container = control as ContainerControl;
    if (container != null)
    {
        ApplyToChildren(container);
    }
}

或者 LINQ to Objects 中的优化(很多这样的例子):

public static int Count<T>(this IEnumerable<T> source)
{
    IList list = source as IList;
    if (list != null)
    {
        return list.Count;
    }
    IList<T> genericList = source as IList<T>;
    if (genericList != null)
    {
        return genericList.Count;
    }

    // Okay, we'll do things the slow way...
    int result = 0;
    using (var iterator = source.GetEnumerator())
    {
        while (iterator.MoveNext())
        {
            result++;
        }
    }
    return result;
}

因此使用 as 就像 is + a 强制转换。正如上面的示例所示,它几乎总是随后与无效检查一起使用。

Use as when it's valid for an object not to be of the type that you want, and you want to act differently if it is. For example, in somewhat pseudo-code:

foreach (Control control in foo)
{
    // Do something with every control...

    ContainerControl container = control as ContainerControl;
    if (container != null)
    {
        ApplyToChildren(container);
    }
}

Or optimization in LINQ to Objects (lots of examples like this):

public static int Count<T>(this IEnumerable<T> source)
{
    IList list = source as IList;
    if (list != null)
    {
        return list.Count;
    }
    IList<T> genericList = source as IList<T>;
    if (genericList != null)
    {
        return genericList.Count;
    }

    // Okay, we'll do things the slow way...
    int result = 0;
    using (var iterator = source.GetEnumerator())
    {
        while (iterator.MoveNext())
        {
            result++;
        }
    }
    return result;
}

So using as is like an is + a cast. It's almost always used with a nullity check afterwards, as per the above examples.

谜兔 2024-12-13 10:39:44

每次当您需要无例外地安全转换对象时,请使用

MyType a = (MyType)myObj; // throws an exception if type wrong

MyType a = myObj as MyType; // return null if type wrong

Every time when you need to safe cast object without exception use as:

MyType a = (MyType)myObj; // throws an exception if type wrong

MyType a = myObj as MyType; // return null if type wrong
望喜 2024-12-13 10:39:44

As 用于避免双重转换逻辑,如下所示:

if (x is MyClass)
{
  MyClass y = (MyClass)x;
}

使用

MyClass y = x as MyClass;
if (y == null)
{
}

仅供参考,为情况 #1 生成 IL:

  // if (x is MyClass)
  IL_0008:  isinst     MyClass
  IL_000d:  ldnull
  IL_000e:  cgt.un
  IL_0010:  ldc.i4.0
  IL_0011:  ceq
  IL_0013:  stloc.2
  IL_0014:  ldloc.2
  IL_0015:  brtrue.s   IL_0020
  IL_0017:  nop
  // MyClass y = (MyClass)x;
  IL_0018:  ldloc.0
  IL_0019:  castclass  MyClass
  IL_001e:  stloc.1

和情况 #2:

  // MyClass y = x as MyClass;
  IL_0008:  isinst     MyClass
  IL_000d:  stloc.1
  // if (y == null)
  IL_000e:  ldloc.1
  IL_000f:  ldnull
  IL_0010:  ceq
  IL_0012:  stloc.2
  IL_0013:  ldloc.2
  IL_0014:  brtrue.s   IL_0018

As is used to avoid double casting logic like in:

if (x is MyClass)
{
  MyClass y = (MyClass)x;
}

Using

MyClass y = x as MyClass;
if (y == null)
{
}

FYI, IL generated for case #1:

  // if (x is MyClass)
  IL_0008:  isinst     MyClass
  IL_000d:  ldnull
  IL_000e:  cgt.un
  IL_0010:  ldc.i4.0
  IL_0011:  ceq
  IL_0013:  stloc.2
  IL_0014:  ldloc.2
  IL_0015:  brtrue.s   IL_0020
  IL_0017:  nop
  // MyClass y = (MyClass)x;
  IL_0018:  ldloc.0
  IL_0019:  castclass  MyClass
  IL_001e:  stloc.1

and for case #2:

  // MyClass y = x as MyClass;
  IL_0008:  isinst     MyClass
  IL_000d:  stloc.1
  // if (y == null)
  IL_000e:  ldloc.1
  IL_000f:  ldnull
  IL_0010:  ceq
  IL_0012:  stloc.2
  IL_0013:  ldloc.2
  IL_0014:  brtrue.s   IL_0018
糖果控 2024-12-13 10:39:44

使用 as 不会抛出强制转换异常,而只是在强制转换失败时返回 null

Using as will not throw a cast exception, but simply return null if the cast fails.

沦落红尘 2024-12-13 10:39:44

Enumerable 中 .Count() 的实现使用它来使 Count() 更快地进行收集。

实现类似于:

        ICollection<TSource> collection = source as ICollection<TSource>;
        if (collection != null)
        {
            return collection.Count;
        }
        ICollection collection2 = source as ICollection;
        if (collection2 != null)
        {
            return collection2.Count;
        }

尝试将源强制转换为 ICollection 或 ICollection 都具有 Count 属性。
如果失败,Count() 将迭代整个源。
因此,如果您不确定类型并且之后需要该类型的对象(如上面的示例),您应该使用 as

如果您只想测试对象是否属于给定类型,请使用 is 并且如果您确定该对象属于给定类型(或派生自/实现该类型),那么您可以强制转换

The implementation of .Count() in Enumerable uses it to make Count() for collection faster

The implementation is like:

        ICollection<TSource> collection = source as ICollection<TSource>;
        if (collection != null)
        {
            return collection.Count;
        }
        ICollection collection2 = source as ICollection;
        if (collection2 != null)
        {
            return collection2.Count;
        }

That tries to cast the source to either ICollection or ICollection both have a Count property.
If that fails Count() iterates the entire source.
So if you are unsure about the type and need the object of the type afterwards (like in the above example) you should use as.

If you only want to test if the object is of a given type use is and if you are sure that the object is of a given type (or derives from/implements that type) then you can cast

梦纸 2024-12-13 10:39:44

好的,很好,大家都回复了,但让我们来点实际的。在您自己的代码(即非供应商代码)中,AS 关键字的真正威力不会凸显出来。

但是,当处理 WPF/silverlight 中的供应商对象时,AS 关键字是一个真正的好处。
例如,如果我在画布上有一系列控件,并且我想跟踪最后一个选定的控件,但是当我单击画布时清除跟踪变量,我会这样做:

private void layoutroot_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
               //clear the auto selected control
        if (this.SelectedControl != null 
            && sender is Canvas && e.OriginalSource is Canvas)
        {
            if ((sender as Canvas).Equals(( e.OriginalSource as Canvas)))
            {
                this.SelectedControl = null;
            }
        }
    }

它使用 AS 关键字的另一个原因是当您的类实现 1 个或多个时接口,并且您只想显式使用一个接口:

IMySecond obj = new MyClass as IMySecond

虽然这里实际上并不需要,但如果 MyClass 未实现 IMySecond,它将为变量 obj 分配 null

Ok Nice replies everyone, but lets get a bit practical. In your own code,ie non-vendor code the REAL power of AS keyword doesn't come to the fore.

But when dealing with vendor objects as in WPF/silverlight then the AS keyword is a real bonus.
for example if I have a series of controls on a Canvas and I want to track track thelast selectedControl, but clear the tracking varaible when I click the Canvas i would do this:

private void layoutroot_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
               //clear the auto selected control
        if (this.SelectedControl != null 
            && sender is Canvas && e.OriginalSource is Canvas)
        {
            if ((sender as Canvas).Equals(( e.OriginalSource as Canvas)))
            {
                this.SelectedControl = null;
            }
        }
    }

Another reason it use AS keyoword is when your Class implements 1 or more Interfaces and you want to explicitly use only one interface:

IMySecond obj = new MyClass as IMySecond

Although not really necessary here, it will assign null to variable obj if MyClass does not implement IMySecond

蓦然回首 2024-12-13 10:39:44

以下是 http://blog 的片段。 nerdbank.net/2008/06/when-not-to-use-c-keyword.html

class SomeType {
    int someField;
    // The numeric suffixes on these methods are only added for reference later
    public override bool Equals1(object obj) {
        SomeType other = obj as SomeType;
        if (other == null) return false;
        return someField == other.SomeField;
    }
    public override bool Equals2(object obj) {
        if (obj == null) return false;
        // protect against an InvalidCastException
        if (!(obj is SomeType)) return false;
        SomeType other = (SomeType)obj;
        return someField == other.SomeField;
    }
}

上面的 Equals1 方法比 Equals2 更高效(并且更容易阅读),尽管它们完成了相同的工作。 Equals1 编译为执行一次类型检查和强制转换的 IL,而 Equals2 编译为首先对“is”运算符执行类型比较,然后作为 () 运算符的一部分一起执行类型比较和强制转换。所以在这种情况下使用“as”实际上更有效。事实上,它更容易阅读是一个好处。

总之,仅当您期望转换在非例外情​​况下失败时才使用 C#“as”关键字。如果您指望强制转换会成功,但没有准备好接收任何失败的对象,则应使用 () 强制转换运算符,以便抛出适当且有用的异常。

Here is a snippet from http://blog.nerdbank.net/2008/06/when-not-to-use-c-keyword.html

class SomeType {
    int someField;
    // The numeric suffixes on these methods are only added for reference later
    public override bool Equals1(object obj) {
        SomeType other = obj as SomeType;
        if (other == null) return false;
        return someField == other.SomeField;
    }
    public override bool Equals2(object obj) {
        if (obj == null) return false;
        // protect against an InvalidCastException
        if (!(obj is SomeType)) return false;
        SomeType other = (SomeType)obj;
        return someField == other.SomeField;
    }
}

The Equals1 method above is more efficient (and easier to read) than Equals2, although they get the same job done. While Equals1 compiles to IL that performs the type checking and cast exactly once, Equals2 compiles to do a type comparison first for the "is" operator, and then does a type comparison and cast together as part of the () operator. So using "as" in this case is actually more efficient. The fact that it is easier to read is a bonus.

In conclusion, only use the C# "as" keyword where you are expecting the cast to fail in a non-exceptional case. If you are counting on a cast to succeed and are unprepared to receive any object that would fail, you should use the () cast operator so that an appropriate and helpful exception is thrown.

沫雨熙 2024-12-13 10:39:44

只是想补充一点,使用 as 后跟 null 检查可以再简化一步:

您可以

MyClass y = x as MyClass;
if (y == null)
{
}

直接

if (x is Myclass y){
    //y is now "MyClass", if x was a different class, we are not even here. 
}

这样做,轻松地允许链接内容:

if (x is Double d){
    //Work with Double d
}else if (x is Int32 i){
    //Work with Int i
}

Just want to add, that the usage of as followed by a null check can be simplified one more step:

instead of

MyClass y = x as MyClass;
if (y == null)
{
}

you can directly do

if (x is Myclass y){
    //y is now "MyClass", if x was a different class, we are not even here. 
}

that easily allows to chain stuff:

if (x is Double d){
    //Work with Double d
}else if (x is Int32 i){
    //Work with Int i
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文