【问题标题】:Extension Method Performance扩展方法性能
【发布时间】:2010-11-03 15:22:27
【问题描述】:
            /*I have defined Extension Methods for the TypeX like this*/ 
        public static Int32 GetValueAsInt(this TypeX oValue)
        {
            return Int32.Parse(oValue.ToString());
        }
        public static Boolean GetValueAsBoolean(this TypeX oValue)
        {
            return Boolean.Parse(oValue.ToString());
        }


         TypeX x = new TypeX("1");
         TypeX y = new TypeX("true");


         //Method #1
         Int32 iXValue = x.GetValueAsInt();
         Boolean iYValue = y.GetValueAsBoolean();

         //Method #2
         Int32 iXValueDirect = Int32.Parse(x.ToString());
         Boolean iYValueDirect = Boolean.Parse(y.ToString());

不要被 TypeX 说我应该在 TypeX 中定义那些方法而不是扩展名而得意忘形)我无法控制它(我定义的实际类在 SPListItem 上。

我想将 TypeX 转换为 Int 或 Boolean,这个操作是我在代码中很多地方都在做的一件常见的事情。我想知道这是否会导致性能下降。我尝试使用 Reflector 解释 IL 代码,但并不擅长。对于上面的示例,可能不会有任何性能下降。一般来说,我想知道在使用扩展方法时对性能的影响。

【问题讨论】:

标签: .net-3.5 c#-3.0


【解决方案1】:

扩展方法会大大影响编译时间。在我参与的一个大型项目中,只需将扩展方法移动到不同的命名空间,我们的编译时间就从 15 分钟缩短到 3 分钟。完全相同的代码,只是复制并粘贴到不同的命名空间。

如果您将编译时间视为“性能”指标的一部分,那么性能肯定会受到影响。作为开发人员,15 分钟的构建时间与 3 分钟的构建时间很重要。

对我们来说主要的问题是我们在几个命名空间中有大量的扩展方法。每个引用臃肿命名空间(使用 using 语句)的类或项目都会导致编译器搜索大量扩展方法。显然,这种搜索不是最优的,并且减慢了 IDE 的速度。 Intellisense 非常缓慢并且变得没有响应。

通过简单地将扩展方法移动到单独的、更细化的命名空间中,编译时间大大缩短。绝对值得考虑。

【讨论】:

    【解决方案2】:

    扩展方法只是一个编译时变化:

    x.GetValueAsBoolean()
    

    Extensions.GetValueAsBoolean(x)
    

    这就是所涉及的全部内容 - 将看起来像实例方法调用的内容转换为对静态方法的调用。

    如果静态方法没有性能问题,那么将其设为扩展方法不会带来任何新问题。

    编辑:IL,根据要求...

    拿这个样本:

    using System;
    
    public static class Extensions
    {
        public static void Dump(this string x)
        {
            Console.WriteLine(x);
        }
    }
    
    class Test
    {
        static void Extension()
        {
            "test".Dump();
        }
    
        static void Normal()
        {
            Extensions.Dump("test");
        }
    }
    

    这是 ExtensionNormal 的 IL:

    .method private hidebysig static void  Extension() cil managed
    {
      // Code size       13 (0xd)
      .maxstack  8
      IL_0000:  nop
      IL_0001:  ldstr      "test"
      IL_0006:  call       void Extensions::Dump(string)
      IL_000b:  nop
      IL_000c:  ret
    } // end of method Test::Extension
    
    .method private hidebysig static void  Normal() cil managed
    {
      // Code size       13 (0xd)
      .maxstack  8
      IL_0000:  nop
      IL_0001:  ldstr      "test"
      IL_0006:  call       void Extensions::Dump(string)
      IL_000b:  nop
      IL_000c:  ret
    } // end of method Test::Normal
    

    如您所见,它们完全相同。

    【讨论】:

    • 如果您只发布了一些示例 IL,您将在此处获得最终解决方案 :)
    • 迄今为止对这个问题最好、最全面的答案
    • Sam 和 Jon,我不懂 IL 示例。转储是我同意的扩展方法。 Extension() 和 Normal() 都做同样的事情。显然它具有相同的 IL
    • 哎呀。编辑 - 正常当然应该调用 Extensions.Dump("test").
    • 现已修复。我重新编译并检查了新的 IL 是否为“Normal”——它真的一点都没有改变。
    【解决方案3】:

    在最坏的情况下,您将有一个额外的函数调用。不过说真的,我希望它应该能够尽可能简单地内联这段代码,并且不会产生任何明显的效果。

    【讨论】:

      【解决方案4】:

      您不会受到任何性能的影响,因为扩展方法都是在编译时绑定的(你怎么说?)。

      【讨论】:

        【解决方案5】:

        扩展方法只是编译器的巫术,因此它们在运行时具有普通方法的所有性能影响。

        【讨论】:

          猜你喜欢
          • 2011-02-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-09-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多