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

本文关键字:任何 优化 是否 返回值 typeof MyControl 缓存 | 更新日期: 2023-09-27 17:58:26

我看到一些本地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编译代码或在运行时,这种方法在性能方面是否有任何好处?

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

typeof的缓存将使您的性能得到小幅提升。下页给出了基准:

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

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

简短回答

是的,它更优化,但不,你不应该使用它,因为在几乎每个的情况下,它都是过早的优化。如果有什么不同的话,如果您多次使用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概念的CLR指令)
  2. RuntimeTypeHandle中获取Type(对Type.GetTypeFromHandle的调用)

将其与将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

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

在您的情况下,我会简单地将类型分配给一个变量,只是为了可读性,而不是为了性能。如果您有性能问题,请首先查看整个过程,通过测量进行隔离,然后从那里开始。

您不太可能在typeof的性能很重要的地方编写代码,因此您应该选择最清晰和可维护的代码样式。