"Esto" en el parámetro de función

88

Mirando algunos ejemplos de código para HtmlHelpers, veo declaraciones que se parecen a:

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

No recuerdo haber visto este tipo de construcción en ningún otro lugar. ¿Alguien puede explicar el propósito de "esto"? Pensé que al declarar algo público estático significaba que la clase no necesitaba ser instanciada, entonces, ¿qué es "esto" en este caso?

chris
fuente

Respuestas:

212

Esta es la sintaxis para declarar métodos de extensión, una nueva característica de C # 3.0.

Un método de extensión es en parte código, en parte compilador "mágico", donde el compilador con la ayuda de intellisense en Visual Studio hace que parezca que su método de extensión está realmente disponible como un método de instancia en el objeto en cuestión.

Déjame dar un ejemplo.

No hay ningún método en la clase String que se llame GobbleGobble, así que creemos un método de extensión:

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

El nombre de la clase es solo mi convención de nomenclatura, no es necesario nombrarlo así, pero tiene que ser estático, al igual que el método.

Después de declarar el método anterior, puede, en Visual Studio, escribir esto:

String s = "Turkey Baster!";
s.

después del punto, espere intellisense y observe que hay un método GobbleGobble allí, complete el código de esta manera:

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

Importante : La clase donde se declara el método de extensión debe estar disponible para el compilador y el procesador intellisense para que intellisense muestre el método. Si escribe GobbleGobble manualmente y usa el acceso directo Ctrl+ ., no lo ayudará a obtener las directivas de uso correctas en el archivo.

Observe que el parámetro del método ha desaparecido. El compilador se moverá silenciosamente por los bits importantes, que son:

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

Por lo tanto, el compilador transformará el código anterior a esto:

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

Entonces, en el momento de la llamada, no tiene nada de mágico, es solo una llamada a un método estático.

Tenga en cuenta que si su método de extensión declara más de un parámetro, solo el primero admite el thismodificador, y el resto debe especificarse como parte de la llamada al método como es normal:

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

Los métodos de extensión se agregaron en parte debido a Linq, donde la sintaxis Linq de C # buscará métodos de extensión con nombres apropiados para los objetos en juego, lo que significa que puede "introducir" el soporte de Linq en cualquier tipo de clase simplemente declarando la extensión correcta métodos. Por supuesto, el soporte completo de Linq es mucho trabajo, pero es posible.

Además, los métodos de extensión por sí mismos son realmente útiles, así que sigue leyendo.

Aquí hay algunos enlaces:

Lasse V. Karlsen
fuente
6
Definitivamente voy a empezar a usar el término "Gobble Gobble Magic".
Chris
Youtube rompió el enlace de nuevo, youtube.com/watch?v=Bz_heb9Rz2g , todavía a la 1:00 en adelante.
Lasse V. Karlsen
Este tipo de magia del compilador dificulta el aprendizaje de un idioma.
Don Dilanga
8

Después de los métodos de extensión, los he estado usando como loco ... aquí hay algunos que uso constantemente ...

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

Funciona así ...

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

Sí, aparece en todos los objetos, puede ser molesto, pero como lo uso para casi todos los tipos de datos, ayuda simplemente adjuntar un objeto en lugar de duplicarlo para todos los tipos de datos posibles.

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>();
jaekie
fuente
6

Se utiliza para métodos de extensión. Básicamente, 'pega' el Helpername al objeto htmlHelper para poder decir:

new HtmlHelper().HelperName(...more regular params);
Henrik Gering
fuente
4

Ese sería un método de extensión. Le permiten "extender" una clase a través de métodos estáticos que viven fuera de la clase original.

Por ejemplo, digamos que tiene un método de cadena útil que usa todo el tiempo ...

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

Y lo llamas ...

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

Eso no es tan malo. Pero con un pequeño cambio, podría convertirlo en un método de extensión y la llamada sería un poco más bonita:

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

Y luego llámalo ...

string allAs = "aaaA";
int count = allAs.CountAllAs();
Justin Niessner
fuente
3

Métodos de extensiones ...

... son una forma fantástica de incluir funcionalidades como si estuvieras usando el patrón de decorador , pero sin el dolor de refactorizar todo tu código, o usar un nombre diferente de un tipo común.

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

Por lo tanto, puede usar este código en cualquier lugar de su aplicación.

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

>> Hello My Friend

Entonces, el atributo de este comando significa el tipo en el que se “agregará” la extensión, y le permitirá trabajar con el valor como si se hubiera pasado como parámetro.

Fraga
fuente