在function参数中“this”

看一些HtmlHelpers的代码示例,我看到如下所示的声明:

public static string HelperName(this HtmlHelper htmlHelper, ...more regular params ) 

我不记得在哪里可以看到这种types的结构 – 有人可以解释“这个”的目的吗? 我认为通过声明一些公共静态的东西意味着这个类不需要被实例化 – 那么在这种情况下什么是“this”呢?

这是用于声明扩展方法的语法,C#3.0的一个新特性。

一个扩展方法是部分代码,部分编译器“魔术”,其中编译器借助Visual Studio中的intellisense使得看起来您的扩展方法实际上可用作所讨论对象上的实例方法。

让我举个例子。

在名为GobbleGobble的String类中没有方法,所以我们来创build一个扩展方法:

 public static class StringExtensions { public static void GobbleGobble(this string s) { Console.Out.WriteLine("Gobble Gobble, " + s); } } 

类名只是我的命名约定,没有必要像这样命名,但它必须是静态的,方法也一样。

声明上述方法之后,您可以在Visual Studio中input以下内容:

 String s = "Turkey Baster!"; s. 

点后,等待intellisense,并注意有一个GobbleGobble方法那里,完成这样的代码:

 String s = "Turkey Baster!"; s.GobbleGobble(); 

重要说明 :声明扩展方法的类必须可供编译器和智能感知处理器使用,以便智能感知显示该方法。 如果您手动inputGobbleGobble,并使用Ctrl + 快捷方式,它不会帮助您正确使用指令到文件中。

请注意,该方法的参数已经消失。 编译器会静静地移动重要的位,它们是:

 String s = "Turkey Baster!"; s.GobbleGobble(); ^ ^ | +-- the compiler will find this in the StringExtensions class | +-- will be used as the first parameter to the method 

因此,上面的代码将被编译器转换为:

 String s = "Turkey Baster!"; StringExtensions.GobbleGobble(s); 

所以在通话时,没有什么神奇的,只是一个静态方法的调用。

请注意,如果您的扩展方法声明了多个参数,则只有第一个支持this修饰符,其余部分必须作为方法调用的一部分指定:

 public static void GobbleGobble(this string value, string extra) { | | ... | | } | | | | +--------------------------------------------+ | | | v | s.GobbleGobble("extra goes here"); | ^ | | | +-----------------------------------+ 

部分原因是Linq增加了扩展方法,C#的Linq语法将为正在使用的对象寻找适当命名的扩展方法,这意味着只要声明正确的扩展就可以将Linq支持“引入”任何types方法。 当然,完整的Linq支持是很多工作,但是这是可能的。

另外,扩展方法本身是非常有用的,所以请阅读它。

这里有几个链接:

  • MSDN:扩展方法(C#编程指南)
  • MSDN杂志 – 基本本能:扩展方法
  • 维基百科:扩展方法

它用于扩展方法。 基本上你把Helpername粘到htmlHelper对象上,所以你可以说:

 new HtmlHelper().HelperName(...more regular params); 

扩展方法后,我一直在使用他们像疯了..这里是我经常使用的一些..

 public static T ChangeType<T>(this object obj) { return (T)Convert.ChangeType(obj, typeof(T)); } 

像这样工作..

 int i = "123".ChangeType<int>(); bool valid = "bool".ChangeType<bool>(); int id = dataSet.Tables[0].Rows[0]["Id"].ChangeType<int>(); 

是的,它显示在每一个对象,可以是烦人的,但因为我用它几乎所有的数据types,它有助于附加一个对象,而不是复制它为每个可能的数据types。

 public static string ToXml(this object serializableObject) { var aMemStr = new MemoryStream(); try { var serializer = new XmlSerializer(serializableObject.GetType()); serializer.Serialize(new XmlTextWriter(aMemStr, null), serializableObject); return Encoding.UTF8.GetString(aMemStr.ToArray()); } finally { if (aMemStr != null) { aMemStr.Dispose(); } } } string xml = dataSet.ToXml(); public static T ToObject<T>(this string xmlString) { var aStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlString)); try { return (T)new XmlSerializer(typeof(T)).Deserialize(aStream); } finally { if (aStream != null) { aStream.Dispose(); aStream = null; } } } DataSet dataSet = xml.ToObject<DataSet>(); 

这将是一个扩展方法。 它们允许您通过静态方法“扩展”一个类,这些方法不在原始类中。

例如,假设你有一个有用的string方法,你所有的时间…

 public int CountAllAs(string orig) { return orig.ToLowerInvariant().ToArray().Count(c => c == 'a'); } 

你叫它…

 string allAs = "aaaA"; int count = CountAllAs(allAs); 

这不是太糟糕。 但是只要稍作改动,你就可以把它变成一个扩展方法,而且调用会更漂亮些:

 public static int CountAllAs(this string orig) { return orig.ToLowerInvariant().ToArray().Count(c => c == 'a'); } 

然后叫它…

 string allAs = "aaaA"; int count = allAs.CountAllAs(); 

扩展方法 …

…是一个很好的方法来包含像使用装饰器模式的地方 ,但没有重构所有代码的痛苦,或使用一个不同的公共types的名称的function。

 public static class Extensions { public static string RemoveComma(this string value) { if (value == null) throw new ArgumentNullException("value"); return value.Replace(",", ""); } } 

所以你可以在你的应用程序的任何地方使用这个代码。

 Console.WriteLine(“Hello, My, Friend”.RemoveComma()) >> Hello My Friend 

因此, 这个命令属性意味着扩展名将被“添加”的types,并让您使用该值作为parameter passing。