【问题标题】:How do extension methods work under-the-hood?扩展方法如何在幕后工作?
【发布时间】:2012-02-06 22:11:27
【问题描述】:

我工作的承包商正在使用extension methods我们拥有的知名内部类上实现CRUD。我说使用普通的inheritance 比使用extension methods 更好,原因如下。

  • 使用扩展方法会混淆、隐藏和混淆CRUD 方法的来源。
  • 我假设extension methods 大量使用reflection(更慢)。

他的逻辑是,“它是编译好的,所以它很快。”也许我错了……但仅仅因为它被编译并不意味着它不使用反射,也不意味着它比普通继承更快。

所以我的问题是:

  1. extension methods 如何在后台工作?
  2. 在您拥有的知名课程上使用inheritanceextension methods 更好吗?

【问题讨论】:

  • 扩展方法只是另一个类中的公共静态方法,具有特定类型的第一个参数。 C# 提供了一些语法糖来允许调用其中一个方法,就好像它是该类型的成员一样。
  • 请记住,当需要子类型关系时应使用继承,而不仅仅是代码重用。

标签: c# asp.net extension-methods


【解决方案1】:

扩展方法在底层是如何工作的?

它们只是静态方法;编译器将myObject.MyExtensionMethod() 之类的调用重写为MyExtensionClass.MyExtensionMethod(myObject)

在您拥有的 WELL-KNOWN 类上使用继承或扩展方法更好吗?

这个问题没有单一的答案,这完全取决于上下文。但通常扩展方法在这些情况下最有用:

  • 您不拥有扩展类型的代码
  • 该方法针对一个接口,并且对于该接口的所有实现都是相同的(例如IEnumerable<T> 和 Linq 扩展方法)

【讨论】:

    【解决方案2】:

    我假设扩展方法大量使用反射(速度较慢)。

    没有。扩展方法在编译时解析,不需要反射。
    这消除了您对性能的担忧。

    使用继承还是扩展方法更好?

    我都不会说。使用存储库 (DAL)。一个实体应该是持久性不可知的(因此:不从执行 CRUD 的基础继承),并且不假装不参与其中(无扩展)。

    您说得对,“使用扩展方法会混淆和混淆 CRUD 方法的来源”,但继承不是解决方案。

    【讨论】:

      【解决方案3】:

      说明

      Extension Methods 是一种语言功能。编译器从中生成常规的IL(又名MSILCIL)代码。无需反射。

      更多信息

      【讨论】:

        【解决方案4】:

        您的问题和现有的答案都忽略了大局。加入正在进行的项目的新开发人员应该符合现有的编码风格和标准,即使他们不是新人的首选。

        如果方法的改变代表了主要的功能改进而不是主要的审美差异,则仍应首先由整个团队进行讨论和批准。

        一旦完成,更改应该被大规模实施并更新样式指南以仅包含新方法,或者旧方法应该被标记为已弃用并在触及包含它的代码时进行现代化改造。在后一种情况下,最好将清理更改与现有功能的添加/删除/修改分开提交,以便清楚为什么要进行差异中的各个修改。

        【讨论】:

          【解决方案5】:

          回答第一个问题:

          在底层,扩展充当委托,因此 void MyExtension(this object obj) 可以重写为 Action MyDelegate。但是,它们的不同之处在于调用时的语法,因为 Action 必须环绕对象,而可以调用扩展,就好像它是对象本身的成员一样,即使在后台它不是(也没有任何直接访问对象的私有或受保护成员)。

          回答第二个问题:

          我通常为我不拥有的类或接口保留扩展。

          例如,假设你有一个接口 IAnimal

          Public Interface IAnimal
          {
              void Speak();
              void RunToOwnerWhenCalled();
          }
          

          还有以下几类

          public class Mammal
          {
              public virtual void AnswerWhatAmI()
              {
                  Console.WriteLine("I'm a mammal");
              }
          }
          
          public class Dog:Mammal, IAnimal
          {
              public void Speak()
              {
                  Console.WriteLine("arf");
              }
          
              public void RunToOwnerWhenCalled()
              {
                  Console.WriteLine("Comming");
              }
          }
          
          public class Cat:Mammal, IAnimal
          {
              public void Speak()
              {
                  Console.WriteLine("meow");
              }
          
              public void RunToOwnerWhenCalled()
              {
                  Console.WriteLine("I don't know you");
              }
          }
          

          然后你可以有一个像这样的扩展

          Public static void CallAnimal(this IAnimal animal)
          {
              animal.RunToOwnerWhenCalled();
          }
          

          还有一个方法

          Public static void Main
          {
              Cat cat = new Cat();
              cat.CallAnimal();
          }
          

          结果会在控制台中显示猫的响应“我不认识你”。

          再考虑一门课

          Public class Human:Mammal
          {
              Public Human():base()
              {
                  Console.WriteLine("To be more specific, I am a human.");
              }
          }
          

          这个类没有 CallAnimal 扩展,因为它没有隐含 IAnimal 接口,即使它是一种哺乳动物。

          【讨论】:

            【解决方案6】:

            在底层,扩展方法就像一个常规方法,调用它的对象作为第一个参数(this 参数)传递。扩展方法没有什么特别之处,它只是语法糖果

            最好尽量避免使用扩展方法。它们降低了代码的可读性和面向对象性。

            如果它是你拥有的类,我认为没有理由向它添加扩展方法。

            【讨论】:

            • 反射法是指扩展法吗?
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-10-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多