大多数情况下,当你想要更改类型时,只需要使用传统的强制转换即可。
var value = (string)dictionary[key];
这很好,因为:
- 它速度快
- 它会报错(而不是抛出“对象为空”异常)
那么,有没有一个很好的例子可以使用 as
运算符呢?我无法找到或想到一个完美适合它的例子。
注意:实际上,我认为有时编译器会阻止使用强制类型转换,但可以使用 as
运算符(与泛型有关?)。
大多数情况下,当你想要更改类型时,只需要使用传统的强制转换即可。
var value = (string)dictionary[key];
这很好,因为:
那么,有没有一个很好的例子可以使用 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
加上一个强制转换。通常在上述示例中之后会进行空值检查。
as
,其中参数可以为null,因此我能够无条件地传递它。不过方法内部可能有一个空值检查 :) 一种变体是与空值合并运算符一起使用,例如:IList<T> list = sequence as IList<T> ?? sequence.ToList();
- Jon Skeet每次需要进行安全转换对象而不出现异常时,请使用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)
{
}
供您参考,针对第一种情况生成的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
// 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()方法实现使用了该技术,使得对集合计数更加高效。
具体实现方式如下:
ICollection<TSource> collection = source as ICollection<TSource>;
if (collection != null)
{
return collection.Count;
}
ICollection collection2 = source as ICollection;
if (collection2 != null)
{
return collection2.Count;
}
as
。is
,如果您确定对象属于给定类型(或派生自/实现该类型),则可以进行强制转换。大家的回复都很好,但让我们更加实际一些。在你自己的代码中,即非供应商代码中,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关键字的另一个原因是当您的类实现了一个或多个接口,并且您只想显式地使用其中一个接口时:
IMySecond obj = new MyClass as IMySecond
虽然这里并不是必需的,但如果 MyClass 没有实现 IMySecond 接口,它会将 null 赋值给变量 obj。
if((sender as Canvas).Equals((e.OriginalSource as Canvas)))
,我认为即使它们都是 null,也可能返回 true,因为它们都不是 Canvas
类型。 - Kieran Bond这里是来自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;
}
}