"Questo" nel parametro funzione


88

Guardando alcuni esempi di codice per HtmlHelpers e vedo dichiarazioni che assomigliano a:

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

Non ricordo di aver visto questo tipo di costrutto da nessun'altra parte - qualcuno può spiegare lo scopo del "questo"? Ho pensato che dichiarare qualcosa di statico pubblico significava che la classe non aveva bisogno di essere istanziata - quindi cos'è "questo" in questo caso?

Risposte:


212

Questa è la sintassi per la dichiarazione dei metodi di estensione, una nuova funzionalità di C # 3.0.

Un metodo di estensione è in parte codice, in parte compilatore "magico", dove il compilatore con l'aiuto di intellisense in Visual Studio fa sembrare che il tuo metodo di estensione sia effettivamente disponibile come metodo di istanza sull'oggetto in questione.

Faccio un esempio.

Non esiste un metodo sulla classe String che si chiama GobbleGobble, quindi creiamo un metodo di estensione:

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

Il nome della classe è solo la mia convenzione di denominazione, non è necessario chiamarlo in questo modo, ma deve essere statico, così come il metodo.

Dopo aver dichiarato il metodo sopra, puoi, in Visual Studio, digitare questo:

String s = "Turkey Baster!";
s.

dopo il punto, attendi intellisense e nota che c'è un metodo GobbleGobble lì, completa il codice in questo modo:

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

Importante : la classe in cui viene dichiarato il metodo di estensione deve essere disponibile per il compilatore e il processore intellisense affinché intellisense possa mostrare il metodo. Se digiti GobbleGobble manualmente e usi la scorciatoia Ctrl+ ., non ti aiuterà a inserire le direttive using corrette nel file.

Notare che il parametro del metodo è scomparso. Il compilatore si muoverà silenziosamente attorno ai bit importanti, che sono:

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

Pertanto, il codice precedente verrà trasformato dal compilatore in questo:

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

Quindi, al momento della chiamata, non c'è niente di magico, è solo una chiamata a un metodo statico.

Nota che se il tuo metodo di estensione dichiara più di un parametro, solo il primo supporta il thismodificatore e il resto deve essere specificato come parte della chiamata al metodo come di consueto:

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

I metodi di estensione sono stati aggiunti in parte a causa di Linq, dove la sintassi Linq di C # cercherà metodi di estensione con nomi appropriati per gli oggetti in gioco, il che significa che puoi "introdurre" il supporto Linq in qualsiasi tipo di classe semplicemente dichiarando l'estensione corretta metodi. Ovviamente, il supporto completo di Linq richiede molto lavoro, ma è possibile.

Inoltre, i metodi di estensione da soli sono davvero utili, quindi continua a leggere.

Ecco alcuni link:


6
Inizierò sicuramente a usare il termine "Gobble Gobble Magic".
chris

Youtube ha interrotto di nuovo il collegamento, youtube.com/watch?v=Bz_heb9Rz2g , ancora all'1: 00 e oltre.
Lasse V. Karlsen,

Questo tipo di magia del compilatore rende difficile l'apprendimento di una lingua.
Don Dilanga,

8

Dopo i metodi di estensione, li ho usati come un matto .. eccone alcuni che uso costantemente ..

public static T ChangeType<T>(this object obj)
{
  return (T)Convert.ChangeType(obj, typeof(T));
}

Funziona così ..

int i = "123".ChangeType<int>();
bool valid = "bool".ChangeType<bool>();
int id = dataSet.Tables[0].Rows[0]["Id"].ChangeType<int>();

Sì, si presenta su ogni singolo oggetto, può essere fastidioso ma poiché lo uso praticamente per tutti i tipi di dati, è utile collegarlo semplicemente a un oggetto piuttosto che duplicarlo per ogni tipo di dati possibile.

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

Viene utilizzato per i metodi di estensione. Fondamentalmente si 'incolla' l'Helpername all'oggetto htmlHelper in modo da poter dire:

new HtmlHelper().HelperName(...more regular params);

4

Quello sarebbe un metodo di estensione. Consentono di "estendere" una classe tramite metodi statici che vivono al di fuori della classe originale.

Ad esempio, supponi di avere un metodo di stringa utile che usi sempre ...

public int CountAllAs(string orig)
{
    return orig.ToLowerInvariant().ToArray().Count(c => c == 'a');
}

E tu lo chiami ...

string allAs = "aaaA";
int count = CountAllAs(allAs);

Non è male. Ma con una piccola modifica, potresti renderlo un metodo di estensione e la chiamata sarebbe un po 'più carina:

public static int CountAllAs(this string orig)
{
    return orig.ToLowerInvariant().ToArray().Count(c => c == 'a');
}

E poi chiamalo ...

string allAs = "aaaA";
int count = allAs.CountAllAs();

3

Metodi di estensione ...

... sono un modo fantastico per includere funzionalità come se stessi utilizzando il pattern decorator , ma senza il dolore di refactoring di tutto il codice o utilizzando un nome diverso di un tipo comune.

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

Quindi puoi usare questo codice, ovunque nella tua app.

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

>> Hello My Friend

Quindi l' attributo this command indica il tipo che l'estensione verrà "aggiunta" e consente di lavorare con il valore come se fosse passato come parametro.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.