查看HtmlHelpers的一些代码示例,我看到如下声明:
public static string HelperName(this HtmlHelper htmlHelper, ...more regular params )
我不记得在其他地方看到过这种类型的构造 - 有人可以解释“这个”的目的吗?我认为通过声明一些公共静态意味着该类不需要实例化 - 所以在这种情况下什么是“this”?
答案 0 :(得分:185)
这是声明扩展方法的语法,扩展方法是C#3.0的一个新功能。
扩展方法是部分代码,部分编译器“魔术”,其中编译器借助Visual Studio中的intellisense使得您的扩展方法实际上可用作相关对象的实例方法。
让我举个例子。
String类上没有名为GobbleGobble的方法,所以让我们创建一个扩展方法:
public static class StringExtensions
{
public static void GobbleGobble(this string s)
{
Console.Out.WriteLine("Gobble Gobble, " + s);
}
}
类名只是我的命名约定,没有必要像这样命名,但它必须是静态的,方法也是如此。
声明上述方法后,您可以在Visual Studio中键入以下内容:
String s = "Turkey Baster!";
s.
点后,等待intellisense,注意那里有一个GobbleGobble方法,完成这样的代码:
String s = "Turkey Baster!";
s.GobbleGobble();
重要:声明扩展方法的类必须可供编译器和智能感知处理器使用,以便intellisense显示该方法。如果您手动输入GobbleGobble,并使用 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-support“引入”任何类型的类中正确的扩展方法。当然,完整的Linq支持是很多工作,但它是可能的。
此外,扩展方法本身非常有用,请仔细阅读。
以下是一些链接:
答案 1 :(得分:7)
在扩展方法之后,我一直在疯狂地使用它们。这里有一些我经常使用的..
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>();
是的,它显示在每个单独的对象上,可能很烦人,但由于我几乎对每种数据类型使用它,因此只需将对象附加到对象而不是为每种可能的数据类型复制它。
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>();
答案 2 :(得分:6)
它用于扩展方法。基本上你将Helpername“粘合”到htmlHelper对象,所以你可以说:
new HtmlHelper().HelperName(...more regular params);
答案 3 :(得分:4)
那将是一个扩展方法。它们允许您通过生活在原始类之外的静态方法“扩展”类。
例如,假设您有一个有用的字符串方法,您一直在使用它......
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();
答案 4 :(得分:3)
...是一种很棒的方式,可以包含使用decorator pattern的功能,但不需要重构所有代码,或者使用不同的常用类型名称。
public static class Extensions
{
public static string RemoveComma(this string value)
{
if (value == null) throw new ArgumentNullException("value");
return value.Replace(",", "");
}
}
因此,您可以在app中的任何位置使用此代码。
Console.WriteLine(“Hello, My, Friend”.RemoveComma())
>> Hello My Friend
因此此命令属性表示扩展名将被“添加”的类型,并允许您使用该值,就像它作为参数传递一样。