0

我有下一节课:

public class A
{
    public int MyProperty { get; set; }
}

Main中的以下代码:

object obj = new A();

Stopwatch sw = Stopwatch.StartNew();
var res = obj as A;
if (res != null)
{
    res.MyProperty = 10;
    Console.WriteLine("obj is A (as)" + sw.Elapsed);
}
sw.Stop();

Stopwatch sw2 = Stopwatch.StartNew();
if (obj.GetType() == typeof(A))
{
    A a = (A)obj;
    a.MyProperty = 10;
    Console.WriteLine("obj is A (GetType)" + sw2.Elapsed);
}
sw2.Stop();

Stopwatch sw3 = Stopwatch.StartNew();
var isA = obj is A;
if (isA)
{
    A a = (A)obj;
    a.MyProperty = 19;
    Console.WriteLine("obj is A (is)" + sw3.Elapsed);
}
sw3.Stop();

Console.ReadKey();

结果是:

obj is A (as) 00:00:00.0000589
obj is A (GetType) 00:00:00.0000024
obj is A (is) 00:00:00.0000006

关键是运算符“is”的工作速度总是比“as”快。为什么'as'比'is'慢?甚至 GetType() 也比 'as' 快。与 'is' 和 GetType() 相比,什么代表导致此类延迟的 'as' 运算符。

4

3 回答 3

4

我猜这是第一个Console.Write必须打开到控制台的流,因此需要更多时间。

无论如何,写到控制台比做一个演员要多得多的时间,所以你不能从你的测试中得出任何关于演员表的结论。

进行十亿次演员阵容并且每次演员都不向控制台写入任何内容,会给您一个更合理的结果:

object obj = new A();
int iterations = 1000000000;

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++) {
  var res = obj as A;
  if (res != null) {
    res.MyProperty = 10;
  }
}
sw.Stop();
Console.WriteLine("obj is A (as)" + sw.Elapsed);

Stopwatch sw2 = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++) {
  if (obj.GetType() == typeof(A)) {
    A a = (A)obj;
    a.MyProperty = 10;
  }
}
sw2.Stop();
Console.WriteLine("obj is A (GetType)" + sw2.Elapsed);

Stopwatch sw3 = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++) {
  var isA = obj is A;
  if (isA) {
    A a = (A)obj;
    a.MyProperty = 19;
  }
}
sw3.Stop();
Console.WriteLine("obj is A (is)" + sw3.Elapsed);

示例输出:

obj is A (as)00:00:00.3937249
obj is A (GetType)00:00:00.3452988
obj is A (is)00:00:01.0193541
于 2013-02-25T10:08:16.330 回答
2

如果显示“as”比“is”慢,则您的测量结果不正确。

不能这样的原因是“as”和“is”关键字都生成了一条isinstIL指令,但是“is”指令生成了对返回值的额外检查。

您不需要执行任何计时来确定这一点,因为您可以使用反射器检查生成的 IL 代码。

例如,这个方法:

static bool isTest(object value)
{
    return value is Random;
}

生成此 IL:

.method private hidebysig static bool isTest(object 'value') cil managed
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: isinst [mscorlib]System.Random
    L_0006: ldnull 
    L_0007: cgt.un 
    L_0009: ret 
}

虽然这样:

static object asTest(object value)
{
    return value as Random;
}

生成:

.method private hidebysig static object asTest(object 'value') cil managed
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: isinst [mscorlib]System.Random
    L_0006: ret 
}

"is" 关键字生成与 "as" 关键字相同的 IL 以及一些附加指令;因此,对于这种用法,“is”必须比“as”慢。

于 2013-02-25T10:39:28.537 回答
1

我认为这可能是因为您也在设置MyProperty,所以第一次这样做时,属性设置器是 JIT 编译的。

尝试运行这段代码,有无注释行,并检查差异:

    object obj = new A();

    // uncomment these lines and see the difference
    // A tmp = new A();
    // tmp.MyProperty = 100;

    Stopwatch sw = Stopwatch.StartNew();
    var res = obj as A;
    if (res != null) {
        res.MyProperty = 10;
    }
    sw.Stop();
    Console.WriteLine("as : " + sw.Elapsed);

    Stopwatch sw2 = Stopwatch.StartNew();
    if (obj.GetType() == typeof(A)) {
        A a = (A)obj;
        a.MyProperty = 10;
    }
    sw2.Stop();
    Console.WriteLine("GetType : " + sw2.Elapsed);

    Stopwatch sw3 = Stopwatch.StartNew();
    var isA = obj is A;
    if (isA) {
        A a = (A)obj;
        a.MyProperty = 19;
    }
    sw3.Stop();
    Console.WriteLine("is : " + sw3.Elapsed);
于 2013-02-25T10:10:41.980 回答