【问题标题】:"this" in function parameter函数参数中的“this”
【发布时间】:2010-06-15 12:49:19
【问题描述】:

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

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

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

【问题讨论】:

    标签: c# asp.net-mvc parameters


    【解决方案1】:

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

    扩展方法是部分代码,部分是编译器“魔术”,其中编译器在 Visual Studio 中的智能感知的帮助下使您的扩展方法看起来实际上可以作为相关对象的实例方法使用。

    让我举个例子。

    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 支持需要做很多工作,但这是可能的。

    另外,扩展方法本身非常有用,所以请仔细阅读。

    这里有几个链接:

    【讨论】:

    • 我肯定会开始使用“Gobble Gobble Magic”这个词。
    • Youtube 再次断开链接,youtube.com/watch?v=Bz_heb9Rz2g,仍然在 @1:00 及以后。
    • 这类编译器魔法让学习语言变得困难。
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      用于扩展方法。基本上,您将 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();
        

        【讨论】:

          【解决方案5】:

          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(",", "");
              }
          }  
          

          因此,您可以在应用中的任何位置使用此代码。

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-10-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-05-30
            • 2021-08-15
            • 2017-02-23
            • 2018-04-26
            相关资源
            最近更新 更多