“это” в параметре функции

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

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

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

79
задан chris 15 June 2010 в 12:49
поделиться

5 ответов

Это синтаксис для объявления методов расширения, новой возможности 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();

Important: Класс, в котором объявлен метод расширения, должен быть доступен компилятору и процессору intellisense, чтобы 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 - это большая работа, но это возможно.

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

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

195
ответ дан 24 November 2019 в 10:06
поделиться

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

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>();
7
ответ дан 24 November 2019 в 10:06
поделиться

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

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

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
ответ дан 24 November 2019 в 10:06
поделиться

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

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

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 означает тип, к которому будет "добавлено" расширение, и позволяет работать со значением, как если бы оно было передано в качестве параметра.

3
ответ дан 24 November 2019 в 10:06
поделиться

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

new HtmlHelper().HelperName(...more regular params);
6
ответ дан 24 November 2019 в 10:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: