"this" w parametrze funkcji

Patrząc na kilka przykładów kodu dla HtmlHelpers, i widzę deklaracje, które wyglądają następująco:

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

Nie pamiętam, żebym widział tego typu konstrukt gdzie indziej - czy ktoś może wyjaśnić cel "tego"? Myślałem, że deklarując coś publicznego statycznego oznacza to, że klasa nie musi być instancjowana - więc co to jest " to " w tym przypadku?

Author: chris, 2010-06-15

5 answers

Jest to składnia do deklarowania metod rozszerzeń, nowa funkcja w C# 3.0.

Metoda rozszerzenia to część kodu, część kompilatora "Magia", gdzie kompilator z pomocą intellisense w Visual Studio sprawia, że wydaje się, że twoja metoda rozszerzenia jest rzeczywiście dostępna jako metoda instancji na danym obiekcie.

Podam przykład.

Nie ma metody na klasie String o nazwie GobbleGobble, więc stwórzmy rozszerzenie "metoda": {]}

public static class StringExtensions
{
    public static void GobbleGobble(this string s)
    {
        Console.Out.WriteLine("Gobble Gobble, " + s);
    }
}

Nazwa klasy to tylko moja konwencja nazewnictwa, nie trzeba jej tak nazywać, ale musi być statyczna, podobnie jak metoda.

Po zadeklarowaniu powyższej metody, możesz w Visual Studio wpisać:

String s = "Turkey Baster!";
s.

Po kropce poczekaj na intellisense i zauważ, że jest tam metoda GobbleGobble, uzupełnij kod w następujący sposób:

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

Important: klasa, w której deklarowana jest metoda rozszerzenia, musi być dostępna dla kompilatora i procesor intellisense, aby intellisense pokazał metodę. Jeśli wpiszesz GobbleGobble ręcznie i użyjesz Ctrl+. Skrót, nie pomoże Ci w poprawnym wpisaniu dyrektyw do pliku.

Zauważ, że parametr metody zniknął. Kompilator po cichu będzie poruszał się po ważnych bitach, którymi są:

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

Tak więc powyższy kod zostanie przekształcony przez kompilator do tego:

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

Więc w czasie rozmowy, nie ma w tym nic magicznego, to tylko wezwanie do statycznej metody.

Zauważ, że jeśli twoja metoda rozszerzenia deklaruje więcej niż jeden parametr, tylko pierwszy obsługuje modyfikator this, a reszta musi być określona jako część wywołania metody jak zwykle:

public static void GobbleGobble(this string value, string extra)
{                                            |              |
    ...                                      |              |
}                                            |              |
                                             |              |
+--------------------------------------------+              |
|                                                           |
v                                                           |
s.GobbleGobble("extra goes here");                          |
                        ^                                   |
                        |                                   |
                        +-----------------------------------+

Extension methods został dodany częściowo ze względu na Linq, gdzie składnia Linq w C# będzie szukać odpowiednio nazwanych metod rozszerzeń dla obiektów w grze, co oznacza, że można "wprowadzić" obsługę Linq do dowolnego typu klasy poprzez zadeklarowanie właściwych metod rozszerzenia. Oczywiście pełne wsparcie Linq to dużo pracy, ale jest to możliwe.

Również metody rozszerzenia same w sobie są naprawdę przydatne, więc przeczytaj o tym.

Oto kilka linków:

 178
Author: Lasse Vågsæther Karlsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-15 13:25:11

Po metodach rozszerzania używam ich jak szalony.. oto kilka, których używam stale..

public static T ChangeType<T>(this object obj)
{
  return (T)Convert.ChangeType(obj, typeof(T));
}
Działa w ten sposób..
int i = "123".ChangeType<int>();
bool valid = "bool".ChangeType<bool>();
int id = dataSet.Tables[0].Rows[0]["Id"].ChangeType<int>();

Tak, pojawia się na każdym pojedynczym obiekcie, może być irytujące, ale ponieważ używam tego dla prawie każdego typu danych, pomaga po prostu dołączyć go do obiektu, a nie powielać go dla każdego możliwego typu danych.

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
Author: jaekie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-15 14:02:21

Jest używany do ekstensjonalnych metod. Zasadniczo "przyklejasz" nazwę pomocnika do obiektu htmlHelper, dzięki czemu możesz powiedzieć:

new HtmlHelper().HelperName(...more regular params);
 6
Author: Henrik Gering,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-15 12:50:54

To byłaby metoda rozszerzenia. Pozwalają one na "rozszerzenie" klasy za pomocą metod statycznych, które żyją poza klasą oryginalną.

Na przykład, powiedzmy, że masz pomocną metodę łańcuchową, której używasz cały czas...

public int CountAllAs(string orig)
{
    return orig.ToLowerInvariant().ToArray().Count(c => c == 'a');
}
I ty to nazywasz...
string allAs = "aaaA";
int count = CountAllAs(allAs);
Nie jest tak źle. Ale z małą zmianą, można by zrobić z niej metodę rozszerzenia i wywołanie byłoby trochę ładniejsze:
public static int CountAllAs(this string orig)
{
    return orig.ToLowerInvariant().ToArray().Count(c => c == 'a');
}
A potem zadzwoń...
string allAs = "aaaA";
int count = allAs.CountAllAs();
 4
Author: Justin Niessner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-15 12:59:41

Metody Rozszerzeń ...

...to fantastyczny sposób na włączenie funkcjonalności, jak w przypadku używania wzoru dekoratora , ale bez bólu refaktoryzacji całego kodu lub używania innej nazwy popularnego typu.

public static class Extensions
{
     public static string RemoveComma(this string value)
     {
         if (value == null) throw new ArgumentNullException("value");
        return value.Replace(",", "");
    }
}  

Więc możesz użyć tego kodu, w dowolnym miejscu w aplikacji.

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

>> Hello My Friend

Więc ten atrybut polecenia oznacza Typ, że rozszerzenie zostanie "dodane" i pozwala pracować z wartością tak, jakby została przekazana jako parametr.

 3
Author: Fraga,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-15 13:04:34