在c#中什么时候应该使用as关键字?
本文关键字:as 关键字 什么时候 | 更新日期: 2023-09-27 18:09:39
当您想要更改类型时,大多数情况下您只想使用传统的强制转换。
var value = (string)dictionary[key];
这很好,因为:
- 它快速
- 它会抱怨,如果有什么是错误的(而不是给出对象是null异常)
那么,使用as
的一个好例子是什么,我真的找不到或想不出什么完全适合它的东西?
注意:实际上,我认为有时在as
工作的情况下,编译器会阻止使用强制转换(与泛型相关?)
使用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强制转换。几乎总是在后面加上null检查,正如上面的例子所示。
每次需要安全强制转换对象时,请使用as
:
MyType a = (MyType)myObj; // throws an exception if type wrong
MyType a = myObj as MyType; // return null if type wrong
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
,对于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
使用as
不会抛出强制转换异常,如果强制转换失败,只返回null
。
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
,如果您确定对象为给定类型(或派生/实现该类型),则可以强制转换
好的,大家回答得很好,但是让我们实际一点。在你自己的代码中,即非供应商的代码中,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
下面是来自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"关键字。如果您指望强制转换成功,并且没有准备好接收任何可能失败的对象,则应该使用()强制转换操作符,以便抛出适当且有用的异常。