函数参数中的“this”

时间:2010-06-15 12:49:20

标签: c# asp.net-mvc parameters

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

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

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

5 个答案:

答案 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)

Extensions Methods ...

...是一种很棒的方式,可以包含使用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

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