我知道这个关键字的功能,但我想知道它是如何在较低级别上工作的.
哪一个更快?他们总能产生相同的结果吗?如果他们这样做,为什么有两种不同的方式?
// Is there an overhead? An internal try catch?
Class123 obj = someobject as Class123;
if (Class123 != null)
{
//OK
}
Run Code Online (Sandbox Code Playgroud)
要么
Class123 obj = null;
if (someobject is Class123)
{
obj = (Class123)someobject;
}
Run Code Online (Sandbox Code Playgroud)
ulr*_*chb 22
as运算符就像一个强制转换操作.但是,如果无法进行转换,则返回null而不是引发异常.请考虑以下表达式:
expression as type
Run Code Online (Sandbox Code Playgroud)
除了表达式仅被计算一次之外,它等效于以下表达式.
expression is type ? (type)expression : (type)null
Run Code Online (Sandbox Code Playgroud)
第一个变种(作为操作数)......
string str1 = strAsObject as string;
if (str1 != null)
{
this.blabla(str1);
}
Run Code Online (Sandbox Code Playgroud)
...编译到这个IL代码:
L_0009: ldloc.1
L_000a: isinst string
L_000f: stloc.2
L_0010: ldloc.2
L_0011: ldnull
L_0012: ceq
L_0014: stloc.s CS$4$0000
L_0016: ldloc.s CS$4$0000
L_0018: brtrue.s L_0024
L_001a: nop
L_001b: ldarg.0
L_001c: ldloc.2
L_001d: call instance void TestWinFormsApplication001.Form1::blabla(string)
L_0022: nop
L_0023: nop
Run Code Online (Sandbox Code Playgroud)
......和第二个变体(操作数+演员)......
if (strAsObject is string)
{
string str2 = (string) strAsObject;
this.blabla(str2);
}
Run Code Online (Sandbox Code Playgroud)
...编译到这个IL代码:
L_0024: ldloc.1
L_0025: isinst string
L_002a: ldnull
L_002b: cgt.un
L_002d: ldc.i4.0
L_002e: ceq
L_0030: stloc.s CS$4$0000
L_0032: ldloc.s CS$4$0000
L_0034: brtrue.s L_0047
L_0036: nop
L_0037: ldloc.1
L_0038: castclass string
L_003d: stloc.3
L_003e: ldarg.0
L_003f: ldloc.3
L_0040: call instance void TestWinFormsApplication001.Form1::blabla(string)
L_0045: nop
L_0046: nop
Run Code Online (Sandbox Code Playgroud)
...所以你看到唯一的区别是castclass排队的附加代码L_0038.
Nol*_*rin 16
使用as关键字时没有内部尝试捕获.据我所知,该功能内置于编译器/ CLR中,因此类型检查是隐式和自动的.
规则很简单:
使用直接铸当你总是期待的对象有一个已知类型(因而收到一个有用的错误,如果它是由错误的类型的机会).as当对象始终是已知类型时,请使用关键字.
as关键字存在的原因纯粹是为了程序员的方便(尽管你建议try-catch会更慢).你可以手动实现它,就像你指出的那样:
var castObj = (obj is NewType) ? (NewType)obj : null;
Run Code Online (Sandbox Code Playgroud)
这突出了'as'关键字主要用于简洁目的的事实.
现在,两者之间的性能差异可能微不足道.该as关键字可能是稍微比较慢,因为类型的检查,但这不太可能在绝大多数情况影响的代码.如上所述,过早优化从来都不是明智之举.基准如果你真的希望,但我建议只是使用哪种方法更方便/适合你的情况,而不是担心性能(或以后,如果你绝对必须).
直截了当地说几件事:
当您确定对象属于您要转换的类型时,应该进行类型转换.它可以为null(在这种情况下,将返回null,除非它是您要转换的值类型)
如果您不确定,可以使用"as"运算符.当对象不可转换,或者对象为null时,将返回null.
"as"运算符转换为专用的IL语句(isinst),而类型转换转换为castclass IL语句,因此它构建在运行时中.编译器只发出正确的IL语句.
这个问题已经得到了很好的回答,但到目前为止它已经缺少了难以理解的数字.
Over 100000000 iterations
AS : Failure 00:00:00.9282403
Cast : Failure 00:00:00.9868966
AS : Success 00:00:00.9350227
Cast : Success 00:00:01.1382759
Run Code Online (Sandbox Code Playgroud)
这些数字一直以这些比例回归
我想指出,从这些数字中得出的唯一结论是,从绩效的角度来看,通过选择其中一种方法而获得的结果很少.单个呼叫的差异很小(非常小的趋势为零).那说,"as"更快:)
在此之后,上述数字大多是有道理的.
"作为"失败的时间比成功时长.成功没有任何反应,可以按原样使用,也可以简单地复制.失败时,需要跳转才能复制空引用.
失败时"强制转换"速度更快,一次调用"是"并且它不再执行任务.成功时它会慢得多,它会对"是"和"演员"进行调整.
但是我很惊讶Cast失败的时间比AS失败的时间长
编辑
根据要求,在try/catch块中投射的数字
Over 100000000 iterations
Catch : Failure 05.05:00:00 // approximately, because I didn't hang around
Catch : Success 00:00:01.4000952
Run Code Online (Sandbox Code Playgroud)
产生第一组数字的代码
class Program
{
const int ITERATION_COUNT = 100000000;
private static UInt64 stringCount = 0;
private static UInt64 objectCount = 0;
static void Main(string[] args)
{
Console.WriteLine("Over {0} iterations ", ITERATION_COUNT);
string s = "Hello";
object o = new Int32();
RunTest("AS : Failure {0}", TestAs, o);
RunTest("Cast : Failure {0}", TestIs_And_Cast, o);
RunTest("AS : Success {0}", TestAs, s);
RunTest("Cast : Success {0}", TestIs_And_Cast, s);
Console.WriteLine("Press any key to stop");
Console.ReadKey();
}
private static void RunTest(string testDescription, Action<object> testToRun, object arg)
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < ITERATION_COUNT; i++)
testToRun(arg);
sw.Stop();
Console.WriteLine(testDescription, sw.Elapsed);
}
static void TestAs(object obj)
{
string s = obj as string;
if (s != null)
stringCount++;
else
objectCount++;
}
static void TestIs_And_Cast(object obj)
{
string s = null;
if (obj is string)
{
s = (string)obj;
stringCount++;
}
else
objectCount++;
}
}
Run Code Online (Sandbox Code Playgroud)