27

当您大多数时候想要更改类型时,您只想使用传统的演员表。

var value = (string)dictionary[key];

这很好,因为:

  • 它很快
  • 如果出现问题,它会抱怨(而不是给对象是空异常)

那么,什么是as我无法真正找到或想到完全适合它的东西的一个很好的例子呢?

注意:实际上我认为有时编译器会阻止使用强制转换as(泛型相关?)。

4

7 回答 7

35

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;
}

所以 usingas就像一个is+ a cast。根据上面的示例,它几乎总是与之后的无效检查一起使用。

于 2011-09-27T08:31:09.050 回答
25

每次当您需要安全地投射对象时,请使用as

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

MyType a = myObj as MyType; // return null if type wrong
于 2011-09-27T08:31:44.523 回答
9

As 用于避免双重转换逻辑,例如:

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

使用

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

仅供参考,IL 为案例 #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

对于案例 #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
于 2011-09-27T08:31:56.810 回答
7

usingas不会抛出强制转换异常,而是null在强制转换失败时简单地返回。

于 2011-09-27T08:31:13.083 回答
2

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,并且您确定对象属于给定类型(或派生自/实现该类型),那么您可以强制转换

于 2011-09-27T08:31:47.193 回答
2

好的尼斯回复大家,但让我们变得有点实际。在您自己的代码中,即非供应商代码中,AS 关键字的真正威力并没有脱颖而出。

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

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,它会将 null 分配给变量 obj

于 2011-12-07T03:12:48.080 回答
0

这是来自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”关键字。如果您指望强制转换成功并且没有准备好接收任何可能失败的对象,则应使用 () 强制转换运算符,以便引发适当且有用的异常。

于 2011-09-27T08:35:10.147 回答