【问题标题】:What are Extension Methods?什么是扩展方法?
【发布时间】:2010-09-29 01:07:37
【问题描述】:

.NET 中的扩展方法是什么?



编辑: 我在Usage of Extension Methods 发布了一个后续问题

【问题讨论】:

  • 对于您的后续,请参阅下面的答案。基本上你会创建扩展而不是使用继承。
  • @Tom Anderson - 所以创建扩展方法的决定主要是基于对源代码的访问?
  • 就我而言,是的。另一个例子是简单,而不是从 System.Windows.Forms.Form 继承并添加方法,然后修改我的所有源代码以使用该基类,我只需编写扩展名,所有表单现在都有它。
  • 也试试看这个问题。 stackoverflow.com/questions/371272/…
  • 这里是关于 c# 扩展方法的简明文章,其中包含足够的信息来帮助您入门:How and when to use Extension Methods in C# and .Net

标签: .net extension-methods


【解决方案1】:

扩展方法是开发人员向他们无法控制的对象“添加”方法的方式。

例如,如果您想向 System.Windows.Forms 对象添加“DoSomething()”方法,由于您无权访问该代码,您只需为表单创建一个扩展方法,使用以下语法。

Public Module MyExtensions

    <System.Runtime.CompilerServices.Extension()> _
    Public Sub DoSomething(ByVal source As System.Windows.Forms.Form)
        'Do Something
    End Sub

End Module

现在您可以在表单中调用“Me.DoSomething()”。

总而言之,这是一种无需继承即可向现有对象添加功能的方法。

【讨论】:

    【解决方案2】:

    扩展方法允许开发者向公众添加新方法 现有 CLR 类型的合同, 无需对其进行子类化或 重新编译原始类型。

    扩展方法有助于融合 “鸭子打字”支持的灵活性 今天在动态语言中很流行 性能和编译时间 强类型验证 语言。

    参考:http://weblogs.asp.net/scottgu/archive/2007/03/13/new-orcas-language-feature-extension-methods.aspx

    这是一个扩展方法的示例(注意第一个参数前面的 this 关键字):

    public static bool IsValidEmailAddress(this string s)
    {
        Regex regex = new Regex(@"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$");
        return regex.IsMatch(s);
    }
    

    现在,可以直接从任何字符串调用上述方法,如下所示:

    bool isValid = "so@mmas.com".IsValidEmailAddress();
    

    添加的方法也会出现在 IntelliSense 中:


    (来源:scottgu.com)

    关于扩展方法的实际用途,您可以在不派生新类的情况下向类添加新方法。

    看看下面的例子:

    public class Extended {
        public int Sum() {
            return 7+3+2;
        }
    }
    
    public static class Extending {
        public static float Average(this Extended extnd) {
            return extnd.Sum() / 3;
        }
    }
    

    如您所见,Extending 类正在向Extended 类添加一个名为 average 的方法。要获得平均值,请调用 average 方法,因为它属于 extended 类:

    Extended ex = new Extended();
    
    Console.WriteLine(ex.average());
    

    参考:http://aspguy.wordpress.com/2008/07/03/a-practical-use-of-serialization-and-extension-methods-in-c-30/

    【讨论】:

    • 100% 正确,尽管我对将扩展方法添加到原始类型(例如不是该类型的基础的字符串)感到不满。因此,我不会将“IsValidEmailAddress”添加到字符串中,但我添加了 Left(int) 和 Right(int)。
    【解决方案3】:

    扩展方法是一种“编译器技巧”,它允许您模拟将方法添加到另一个类,即使您没有它的源代码。

    例如:

    using System.Collections;
    public static class TypeExtensions
    {
        /// <summary>
        /// Gets a value that indicates whether or not the collection is empty.
        /// </summary>
        public static bool IsEmpty(this CollectionBase item)
        {
            return item.Count == 0;
        } 
    }
    

    理论上,所有集合类现在都包含一个 IsEmpty 方法,如果该方法没有项目,则返回 true(前提是您已包含定义上述类的命名空间)。

    如果我错过了什么重要的事情,我相信有人会指出来。 (请!)

    当然,关于扩展方法的声明也是有规则的(它们必须是静态的,第一个参数必须在this关键字之前,等等)。

    扩展方法实际上并不修改它们看起来要扩展的类;相反,编译器会破坏函数调用以在运行时正确调用该方法。但是,扩展方法正确显示在智能感知下拉列表中,带有一个独特的图标,您可以像使用普通方法一样记录它们(如上所示)。

    注意:如果方法已存在且具有相同的签名,则扩展方法从不替换方法。

    【讨论】:

    • 最佳解释。谢谢迈克。
    【解决方案4】:

    这是 VB.Net 中的示例;注意 Extension() 属性。将其放在项目中的模块中。

    Imports System.Runtime.CompilerServices
    <Extension()> _
    Public Function IsValidEmailAddress(ByVal s As String) As Boolean
        If String.IsNullOrEmpty(s) Then Return False
    
        Return Regex.IsMatch(email, _
             "^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$")
    End Function
    

    【讨论】:

      【解决方案5】:

      这个问题已经得到解答,但我想补充一点,如果您有其他项目中的类型并且您不想返回该项目以添加一些类型,这将非常有用功能。我们正在使用 NHibernate,并且有一个项目用于我们的数据持久层,人们希望保持清洁。为了在这些对象上获得更好的和可发现的附加方法,我能够使用扩展方法,它真的让我的一天变得更加美好。

      另外,由于没有其他人发布它,这里有一篇关于它的好文章在 MSDN -http://msdn.microsoft.com/en-us/library/bb383977.aspx

      【讨论】:

        【解决方案6】:

        扩展方法 - 简单说明

        即使您无权访问原始源代码,您也可以为某些东西添加方法。让我们考虑一个例子来解释这一点:

        示例:

        假设我有一只狗。所有的狗——所有狗类动物——都会做某些事情:

        1. 吃
        2. WagsTail
        3. 喊“汪/弓/汪!”等等

        狗能做的事,统称为“方法”。现在让我们假设 OO Heaven 中的 Great Programmer 忘记在 dog 类中添加一个方法:FetchNewspaper()。你希望能够说:

        rex.FetchNewspaper(); // or
        beethoven.FetchNewspaper(); 
        

        ......即使您不有权访问源代码。

        您如何让您的狗这样做?您唯一的解决方案是创建“扩展方法”。

        创建扩展方法

        (注意下面第一个参数前面的“this”关键字):

        public static void FetchNewsPaper(this Dog familyDog)
        {
             Console.Writeline(“Goes to get newspaper!”)
        }
        

        如果你想让你的狗得到报纸,只需这样做:

        Dog freddie_the_family_dog = new Dog();
        
        freddie_the_family_dog.FetchNewspaper();
        

        您可以在类中添加方法而无需源代码。这非常方便!

        【讨论】:

          【解决方案7】:

          我想我会添加一个更具概念性且更少依赖代码的解释。

          想象一辆福特汽车驶下施工生产线。您无法使用施工线,但您希望所有福特汽车都能够在汽车后部添加额外的扰流板(展示时看起来更酷)。你打算怎么做?在计算世界中,除非您可以使用福特工厂内的原始施工线,否则您不能只是将东西用螺栓固定到福特上。现在你可以:输入扩展方法。

          现在你可以这样做了:

          Ford hilux = new Ford();
          
          hilux.DisplayRearFoiler(); // you can now do this even though you don't have access to the Ford source code.
          

          您必须创建扩展方法。参考以上答案。

          【讨论】:

            【解决方案8】:

            我想用密封类来回答扩展方法。

            假设您有一个包含重要方法的密封类。您现在想向它添加一个新方法。假设这个类在一个外部 DLL 中,所以你不能向它添加新方法。你会做什么 ?

            再举一个例子。假设您的项目经理或安全大师在您的应用程序中构建了该类。只有在获得项目经理或安全专家的许可后,您才能编辑该类。

            您的解决方案可能是从此类中删除密封关键字,然后 在其他类中继承它。然后在子类(继承此类)中,您可以添加新方法。

            但请稍等 -> 您不能简单地删除密封关键字,因为这会危及整个应用程序的安全性。我敢打赌,您的 PM 或安全专家永远不会以安全问题为由授予您该权限。

            那么在这里可以做什么呢?

            答案是扩展方法,它可以添加到静态类中,您甚至不需要再接触密封类。

            示例:-

            sealed class MyData
            {
                private double D1, D2, D3;
                public MyData(double d1, double d2, double d3)
                { D1 = d1; D2 = d2; D3 = d3; }
                public double Sum() { return D1 + D2 + D3; }
            }
            
            static class ExtendMyData
            {
                public static double Average(this MyData md)
                {
                    return md.Sum() / 3;
                }
            }
            

            我已将一个名为 Average 的公共静态方法添加到一个新的静态类中。该方法有主类的参数,前面有'this'关键字。

            现在调用Average方法我使用父密封类的对象而不是子类。

             MyData md = new MyData(3, 4, 5);
             double exAverage = md.Average();
            

            希望您发现扩展方法有用。

            【讨论】:

              【解决方案9】:

              C#中的扩展方法

              什么是扩展方法?

              Extension method means Class name and method name are having with Static Key word.
              

              使用“this”关键字的扩展方法,第一个签名应该是提及识别地址,这个类型必须与like相同,

              公共静态字符串 Meth(这个字符串 i,int j)

              和

              字符串 res = "ae".Meth(num);

              粗体部分为识别地址。命名空间应该相同。

              为什么我们需要扩展?

              我们在很多地方都使用了相同的功能,后来找不到我们在这里使用的原因。为此使用地址标识。静态意味着单个实例。这只能访问静态成员函数。甚至在静态类中没有静态类方法如何访问?例如:参见“Sal”方法中的抛出错误,

              静态类 Emp { 公共 int Sal(int i,int j) { 返回 i * j; } }

              仅访问静态成员。还有

              enter image description here

              以下代码我们无法在静态类中为非静态类创建对象。那么如何将非静态方法访问到静态类中。为此,我们遵循不继承的扩展方法。

              例如,在这里使用扩展方法添加或什至功能,

              使用系统。文字;

              使用 System.Threading.Tasks;

              命名空间扩展方法 { 静态类程序 {

                  public static string Meth (this string i,int j)
                  {
                      if (j % 2 == 0)
                      {
                          return "Even";
                      }
                      else
                      {
                          return "ODD";
              
                      }
                  }
              
              
              }
              class program2
              {
                  static void Main (string [] args)
                  {
                      Console. WriteLine ("Enter Integer");
                      int num = Convert.ToInt32(Console.ReadLine());
              
                      string res = "ae".Meth(num);
              
                      Console. WriteLine(res);
                      Console.ReadLine();
                  }
              }
              

              结果:

              enter image description here

              【讨论】:

                【解决方案10】:

                有时我们想将我们自己的附加功能添加到一个类型中,并将它们用作该类型上的常用实例方法。如果我们有源代码,我们可以轻松添加新功能而无需创建扩展方法。但是当我们没有源代码并且仍然想添加和调用附加功能作为类型上的实例方法时,就会出现问题;扩展方法用于将我们自己的功能添加到类型中并在源代码不可用时将它们用作该类型的实例方法。

                当我们想要添加自己的功能时,我们甚至可以创建一个单独的静态类并在我们的代码中调用它的静态方法而不是创建扩展方法,但问题可能是代码可读性。

                LINQ 极大地受益于扩展方法。

                它们在开发时非常有用,因为使用 Intellisense 可以轻松地为多个开发人员提供所需的方法;而对于静态方法,我们每次都必须在代码中编写 className.MethodName()。

                【讨论】:

                • 感谢您的好回答。您回答的问题已有将近 10 年的历史,并且已经接受了答案。为确保您获得应得的支持,请考虑包括此答案与其他答案的区别。
                【解决方案11】:

                扩展方法是我们可以将方法添加到现有数据类型的技术。下面是我们如何向现有数据类型添加方法的示例。

                1. 我们创建了一个扩展方法类,我们在其中创建了各种扩展方法

                代码:

                public static class ExtensionMethods
                {
                    public static int WordCount(this string str)
                    {
                        return str.Split(' ').Count();
                    }
                
                    public static int LongestWord(this string str)
                    {
                        return str.Split(' ').Select(x =>
                                x.Length).OrderByDescending(y =>
                                y).FirstOrDefault();
                    }
                }
                
                1. 下面是我们调用上述类中指定的扩展方法的程序类。

                代码:

                public static void Main(String[] args)
                {
                    string str = "this is my name    punit";
                    int i = str.LongestWord();
                }
                

                重点:

                • 扩展方法类需要是静态的

                • 扩展方法的第一个参数将包含 this 关键字,并且该方法也应该是静态的

                【讨论】:

                  【解决方案12】:

                  扩展方法是一种特殊的静态方法。它允许我们在现有类型中添加方法,而无需修改现有类型。 例如。如果您有 Customer 类,并且您需要在其中添加一个方法而无需在 Customer 类中进行修改,对于这种情况,我们有扩展方法。 有关更多示例,请参阅此链接 https://princesid85.wixsite.com/website/home/you-ve-been-holding-your-pen-wrong-your-entire-life

                  【讨论】:

                    【解决方案13】:
                    /// <summary>
                    /// External Library Code
                    /// </summary>
                    namespace ExternalLibrary
                    {
                        public class Calculator
                        {
                            public int Number1 { get; set; }
                            public int Number2 { get; set; }
                    
                            public int Addition()
                            {
                                return Number1 + Number2;
                            }
                    
                            public int Subtraction()
                            {
                                return Number1 - Number2;
                            }
                        }
                    }
                    

                    using ExternalLibrary;
                    using System;
                    
                    namespace StackOverFlow
                    {
                        class Program
                        {
                            static void Main(string[] args)
                            {
                                Calculator calc = new Calculator()
                                {
                                    Number1 = 5,
                                    Number2 = 3
                                };
                                Console.WriteLine(calc.Addition());
                                Console.WriteLine(calc.Subtraction());
                    
                                // Here we want multiplication also. but we don't have access Calculator
                                // class code, so we can't modify in that.
                                // In order to achieve this functionality we can use extension method.
                                Console.WriteLine(calc.Multiplication());
                    
                                Console.ReadLine();
                            }
                        }
                    
                        /// <summary>
                        /// Extension Method for multiplication
                        /// </summary>
                        public static class CalculatorExtension
                        {
                            public static int Multiplication(this Calculator calc)
                            {
                                return calc.Number1 * calc.Number2;
                            }
                        }
                    }
                    

                    【讨论】:

                    • 代码示例总是一个很好的答案。但是,当有关于该代码如何改进/修复问题的支持性评论时,答案的质量会大大提高。
                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2020-08-18
                    • 1970-01-01
                    • 1970-01-01
                    • 2020-02-13
                    • 2013-03-01
                    • 2010-11-25
                    相关资源
                    最近更新 更多