什么是扩展方法?

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

编辑:我已经发布了后续使用扩展方法的问题

扩展方法允许开发人员将新方法添加到现有CLRtypes的公共契约中,而不必对其进行子类化或重新编译原始types。

扩展方法有助于将dynamic语言中stream行的“duck typing”支持的灵活性与强types语言的性能和编译时validation相结合。

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

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

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

现在,上面的方法可以直接从任何string中调用,就像这样:

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

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

替代文字blogposts/extensionmethods/step1.jpg

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

看看下面的例子:

 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/

我为什么要写另一个答案?

上面的答案太复杂了。 我猜如果你需要问什么是扩展方法,你不会真正知道什么是(i)公共契约,(ii)CLR,(iii)types,(iv)子类,( v)鸭子等等

让我们保持简单 – 扩展方法的解释

假设我有一只狗。 一只狗是一种“types”的动物。 所有的狗 – 所有types的狗 – 做某些事情:

  1. WagsTail
  2. 喊“Woof!”
  3. 摇动爪子等

狗可以做的事情都被称为“方法”。

现在让我们假设在OO天堂的大程序员忘了给狗课增加一个方法。 假设你想让你家里的所有狗做额外的事情:FetchNewspaper。

你想能够说:

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

……即使你没有访问源代码。 沃尔夫,雷克斯和贝多芬是你的宠物家庭btw狗。

你最近怎样才能让你的狗做到这一点?

你将不得不重新编译。 但是你没有源代码! 如果您没有源代码,则无法将该方法添加到代码中的相关位置。

你唯一的解决办法是创build一个“扩展方法”。

创build扩展方法

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

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

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

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

如果你没有扩展方法,那么你就不能要求Freddie_the_family_dog取得报纸。

我们刚刚做了什么?

我们增加了一个额外的方法,让所有的狗都有能力拿到报纸。

它是如何工作的?

你只是:(i)打电话给你的狗,和(ii)告诉他取纸。 你不能做的就是说“取一张报纸”,而不是指定在你的家庭中哪只狗应该抓取。

我希望能帮到你。 如果你仍然有问题发表评论,我会尽我所能解释。

扩展方法是开发人员将方法“添加”到无法控制的对象的方法。

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

 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()”。

总而言之,这是一种在没有inheritance的情况下为现有对象添加function的方法。

扩展方法是一种“编译技巧”,即使您没有源代码,也可以模拟向另一个类添加方法。

例如:

 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关键字为前提,等等)。

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

注意:如果方法已经存在相同的签名,则扩展方法从不replace方法。

这里是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 

这个问题已经被回答了,但是我想补充一点,如果你已经有了另一个项目中的types,并且你不想回到那个项目来添加一些function,那么这个问题是非常有用的。 我们正在使用NHibernate,并为我们的数据持久层提供了一个项目,他们希望保持清洁。 为了得到好的和可发现的额外方法到这些对象,我能够使用扩展方法,它真的让我更加开心。

此外,由于没有其他人发布它,这是一个关于它在MSDN上的一个很好的文章 – http://msdn.microsoft.com/en-us/library/bb383977.aspx

我想我会添加一个更概念化的解释,并且不太依赖代码。

想象一下,福特公司正在推行build设线。 您无法进入施工线,但您希望所有福特汽车能够在汽车后部增加一个扰stream板(显示时看起来更酷)。 你打算怎么做? 在计算机世界里,除非你有机会接触到福特工厂的原始生产线,否则你不能只是把东西拉向福特。 那么现在你可以:input扩展方法。

现在你可以做这样的事情:

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

您将不得不创build扩展方法。 参考上面的答案。

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

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

再举一个例子。 假设这个类是由你的项目经理或者安全专家构build的。 只有获得项目经理或安全专家的许可,才能编辑该课程。

您的解决scheme可能是从该类中删除密封关键字,并在其他类中inheritance。 然后在子类(inheritance这个类)里面,你可以添加你的新方法。

但等待 – >你不能简单地删除密封关键字,因为这可能会危及整个应用程序的安全性。 我可以打赌,你的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(); 

希望你find扩展方法有用。