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

Cod*_*ked 22 .net c# optimization

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

static MyControl {
    Type typeFromHandle = typeof(MyControl);

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

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

static MyControl {
    SomeProperty.OverrideMetadata(typeof(MyControl), ...);
    CommandManager.RegisterClassInputBinding(typeof(MyControl), ...);
    EventManager.RegisterClassHandler(typeof(MyControl), ...);
}
Run Code Online (Sandbox Code Playgroud)

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

Col*_*inE 18

缓存typeof将为您带来小的性能提升.在以下页面给出的基准:

Typeof expression used: 2.55 ns
Type object cached:     0.64 ns
Run Code Online (Sandbox Code Playgroud)

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

  • 参考文章指出“C# 语言中的 typeof 运算符实际上最终使用了类型指针上简单而快速的反射形式”,但我开始质疑它的可靠性。我找不到任何其他参考资料,所以我倾向于同意。 (2认同)

cas*_*One 13

简短的回答

是的,它更优,但不,你不应该使用它,因为在几乎所有情况下它都是过早的优化.如果有的话,如果你typeof(MyControl)多次使用它,可以用它来保持代码的可读性.

答案很长

如果您查看从typeof(MyControl)C#中的语句生成的IL ,您会看到以下内容:

IL_0001: ldtoken [mscorlib]MyControl
IL_0006: call class [mscorlib]System.Type
        [mscorlib]System.Type::GetTypeFromHandle(
            valuetype [mscorlib]System.RuntimeTypeHandle)
Run Code Online (Sandbox Code Playgroud)

这些说明执行以下操作:

  1. RuntimeTypeHandle(ldtokenIL指令)加载到堆栈(CLR one,而不是C#/ .NET概念之一).
  2. 获取TypeRuntimeTypeHandle(调用Type.GetTypeFromHandle).

将此与指定Type变量类型与存储在实例中的类型进行比较:

IL_0014: ldloc.2
Run Code Online (Sandbox Code Playgroud)

注意,位置(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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

为了解决这个问题,他们有一个单独的实例,当他们确切知道哪些值将被装箱/取消装箱时,它们被装箱/取消装箱; 用a bool,很容易,只有truefalse.

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

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


Dav*_*nan 5

这是不太可能在那里typeof运算的性能显著,所以你应该选择的代码风格,是最清晰的,可维护你会写代码.