缓存typeof(MyControl)的返回值是否提供任何优化?

时间:2011-06-02 13:40:19

标签: c# .net optimization

我看到类似于以下代码的一些原生WPF控件:

static MyControl {
    Type typeFromHandle = typeof(MyControl);

    // Which is used in various places
    SomeProperty.OverrideMetadata(typeFromHandle, ...);
    CommandManager.RegisterClassInputBinding(typeFromHandle, ...);
    EventManager.RegisterClassHandler(typeFromHandle, ...);
}

似乎以下代码具有相同的性能:

static MyControl {
    SomeProperty.OverrideMetadata(typeof(MyControl), ...);
    CommandManager.RegisterClassInputBinding(typeof(MyControl), ...);
    EventManager.RegisterClassHandler(typeof(MyControl), ...);
}

在JIT代码或运行时期间,这种方法是否提供了任何性能优势?

3 个答案:

答案 0 :(得分:18)

typeof的缓存将为您带来小的性能提升。 following page gives基准:

Typeof expression used: 2.55 ns
Type object cached:     0.64 ns

如果你typeof很多,或者关心纳秒,那么这对你来说可能很重要!

答案 1 :(得分:13)

简短回答

是的,它更优,但不,你不应该使用它,因为几乎每个情况下它是一个不成熟的优化。如果您使用typeof(MyControl)多次,请将其用作保持代码可读性的方法。

答案很长

如果你看一下C#中typeof(MyControl)语句产生的IL,你会看到以下内容:

IL_0001: ldtoken [mscorlib]MyControl
IL_0006: call class [mscorlib]System.Type
        [mscorlib]System.Type::GetTypeFromHandle(
            valuetype [mscorlib]System.RuntimeTypeHandle)

这些说明执行以下操作:

  1. RuntimeTypeHandleldtoken IL指令)加载到堆栈中(CLR一,而不是C#/。NET概念)。
  2. Type(致电Type.GetTypeFromHandle)获取RuntimeTypeHandle
  3. 将此与指定Type变量类型与存储在实例中的类型进行比较:

    IL_0014: ldloc.2
    

    注意,位置(1,2等)将根据其他变量而变化,但最终,它是参考类型的负载。

    比较两者,对已经分配的变量的调用总是会更快。第一个必须加载类型句柄,然后必须调用方法才能将句柄解析为Type;第二种方法只是对局部变量的引用。

    然而,像大多数其他帖子一样,这绝对可以被视为过早优化的情况,因此如果您认为您的代码表现不佳,我建议不要这样做。

    从代码重用的角度来看,可以做出更好的论证,就像你必须改变类型一样,你可以在更少的地方改变它;你不会充斥着typeof陈述的海洋。

    最后,关于WPF,考虑到性能要求(就像任何UI系统一样),这是他们必须要做的事情; WPF拥有大量的托管对象,与Windows窗体相比还要多得多,并且必须考虑这些对象的性能,以便尽可能快地呈现UI。

    结果,你会看到这样的东西:

    private static readonly object TrueObject = true;
    private static readonly object FalseObject = false;
    
    // Later on.
    DoSomething(condition ? TrueObject : FalseObject);
    
    // Where
    void DoSomething(object value)
    {
        // Compare to true/false objects.
        if (value == TrueObject)
        {
            // True case.
        }
        else if (value == FalseObject)
        {
            // False case.
        }
        else
        {
            // Invalid.
            throw new InvalidOperationException();
        }
    }
    

    原因很简单;大多数WPF使用对象作为参数而不是强类型值公开属性/方法。当涉及到值类型时,它可能涉及大量的装箱/拆箱。

    为了解决这个问题,他们有一个实例,当他们知道确切地将哪些值打包/取消装箱时,这些实例会被装箱/取消装箱;使用bool,很容易,只有truefalse

    同样,对于几乎任何系统,我不一定会推荐这种方法,但对于某些系统,它是有道理的。

    在您的情况下,我只是将类型分配给变量,仅用于可读性目的,而不是用于性能。如果您遇到性能问题,请先查看整个过程,通过测量进行隔离,然后从那里开始。

答案 2 :(得分:5)

你不太可能编写typeof性能显着的代码,所以你应该选择最清晰和可维护的代码风格。