“Це” у параметрі функції


88

Переглядаючи деякі приклади коду для HtmlHelpers, я бачу декларації, які виглядають так:

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

Я не пам’ятаю, щоб десь ще бачив такий тип конструкції - хтось може пояснити мету цього? Я думав, що оголошуючи щось загальнодоступним статичним, означає, що клас не потрібно створювати за допомогою екземпляра - то що в цьому випадку "це"?

Відповіді:


212

Це синтаксис оголошення методів розширення, нової функції 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, щоб 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 - це багато роботи, але це можливо.

Крім того, методи розширення самі по собі дійсно корисні, тому прочитайте про них.

Ось кілька посилань:


6
Я безумовно збираюся почати використовувати термін "Gobble Gobble Magic".
Кріс

Youtube знову розірвав посилання, youtube.com/watch?v=Bz_heb9Rz2g , все ще о @ 1: 00 і далі.
Лассе В. Карлсен,

Така магія компілятора ускладнює вивчення мови.
Дон Діланга,

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

Отже, атрибут this command означає тип, до якого буде додано розширення, і дозволить вам працювати зі значенням так, ніби воно передане як параметр.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.