«это» в параметре функции - PullRequest
76 голосов
/ 15 июня 2010

Глядя на некоторые примеры кода для HtmlHelpers, я вижу объявления, которые выглядят так:

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

Я не могу вспомнить, чтобы этот тип конструкции был где-либо еще - может кто-то объяснить цель "этого"? Я думал, что объявление чего-то общедоступного static означает, что класс не нуждается в создании экземпляра - так что же такое «это» в этом случае?

Ответы [ 5 ]

187 голосов
/ 15 июня 2010

Это синтаксис для объявления методов расширения, новой функции C # 3.0.

Метод расширения - это код части, «магия» компилятора части, где компилятор с помощью intellisense в 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.

после точки, дождаться intellisense и заметить, что там есть метод GobbleGobble, завершить код, подобный этому:

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

Важно : класс, в котором объявлен метод расширения, должен быть доступен для компилятора и процедуры intellisense.ssor для того, чтобы 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, где синтаксис Linq для C # будет искать подходящие имена методов расширения для объектов в игре, что означаетВы можете «внедрить» Linq-поддержку в любой тип класса, просто объявив правильные методы расширения.Конечно, полная поддержка Linq - большая работа, но это возможно.

Кроме того, методы расширения сами по себе действительно полезны, так что читайте об этом.

Вот несколько ссылок:

7 голосов
/ 15 июня 2010

После методов расширения я использую их как сумасшедшие ... вот некоторые из них, которые я использую постоянно ..

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 голосов
/ 15 июня 2010

Используется для расширения методов. По сути, вы «склеиваете» имя помощника с объектом htmlHelper, так что вы можете сказать:

new HtmlHelper().HelperName(...more regular params);
4 голосов
/ 15 июня 2010

Это был бы метод расширения.Они позволяют вам «расширять» класс с помощью статических методов, которые находятся вне исходного класса.

Например, скажем, у вас есть полезный строковый метод, который вы используете все время ...

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 голосов
/ 15 июня 2010

Методы расширений ...

... - это фантастический способ включить функциональность, как если бы вы использовали шаблон декоратора , но без трударефакторинг всего вашего кода или использование другого имени общего типа.

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

Так что этот атрибут команды означает тип, в который расширение будет «добавлено», и позволит вам работать со значением, как если бы оно было передано в качестве параметра.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...