功能参数中的“ this”


88

查看HtmlHelpers的一些代码示例,然后看到类似以下的声明:

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

我不记得在其他地方看到过这种类型的构造-有人可以解释“这个”的目的吗?我认为声明公共静态变量意味着不需要实例化该类-那么在这种情况下“ this”是什么?

Answers:


211

这是声明扩展方法的语法,这是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.

点之后,等待智能感知,并注意到那里有一个GobbleGobble方法,请完成如下代码:

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

重要说明:声明扩展方法的类必须对编译器和智能感知处理器可用,以便智能感知显示该方法。如果您手动输入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支持到任何类型的类中方法。当然,完全的Linq支持是很多工作,但有可能。

此外,扩展方法本身确实非常有用,因此请继续阅读。

这里有一些链接:


6
我肯定会开始使用“ Gobble Gobble Magic”一词。
克里斯2010年

YouTube仍在@ 1:00及以后从youtube.com/watch?v=Bz_heb9Rz2g再次断开链接。
Lasse V. Karlsen

这些编译器魔术使学习语言变得困难。
Don Dilanga

8

经过扩展方法,我一直在疯狂地使用它们。..这是我经常使用的一些..

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>();

6

它用于扩展方法。基本上,您可以将Helpername粘贴到htmlHelper对象,这样您就可以说:

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

4

那将是一种扩展方法。它们使您可以通过原始类外部的静态方法来“扩展”一个类。

例如,假设您有一个一直在使用的有用的字符串方法...

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

你叫它...

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

还算不错 但是,只需稍作更改,就可以将其设为Extension方法,并且调用会更漂亮:

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

然后叫它

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

3

扩展方法...

...是一种包含功能的绝妙方式,例如,如果您在哪里使用装饰器模式,而无需重构所有代码或使用不同的通用类型名称。

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

因此,命令属性表示扩展名将被“添加”的类型,并让您像使用值作为参数一样使用该值。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.