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

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

var value = (string)dictionary[key]; 

这很好,因为:

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

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

注意:实际上我认为有时候编译器会阻止使用演员as作品(generics相关?)。

使用时对象对象不是您想要的类型,并且如果是,则要采取不同的行为。 例如,在某些伪代码中:

 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(this IEnumerable source) { IList list = source as IList; if (list != null) { return list.Count; } IList genericList = source as IList; 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是一个+是演员。 根据上面的例子,它几乎总是在之后使用无效检查。

每次当您需要安全施放对象时无例外地使用:

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

用于避免双重投射逻辑,如:

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

运用

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

为案例#1生成的FYI,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不会抛出强制转换exception,但只要在强制转换失败时返回null

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

实现如下:

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

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

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

Ok Nice回复所有人,但让我们有点实用。 在您自己的代码中,即非供应商代码,AS关键字的REALfunction不会脱颖而出。

但是当在WPF / silverlight中处理供应商对象时,AS关键字是一个真正的奖励。 例如,如果我在Canvas上有一系列控件并且我想跟踪thelast selectedControl,但是当我单击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 keyoword的另一个原因是当您的Class实现了一个或多个Interfaces并且您希望显式只使用一个接口时:

 IMySecond obj = new MyClass as IMySecond 

虽然这里没有必要,但如果MyClass没有实现IMySecond,它将为变量obj赋值null

以下是来自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”关键字,在非特殊情况下,您希望转换失败。 如果你指望一个强制转换成功并且没有准备接收任何失败的对象,你应该使用()强制转换运算符,以便抛出适当且有用的exception。