2012-04-04 17 views
9
public static class MyClass 
{ 
    public static void Print<T>(this T theObject) 
    { 
     Console.WriteLine("The print output is " + theObject.ToString()); 
    } 
} 

En la clase dada he especificado un tipo genérico para extender a través de la palabra clave this. Siendo que he retrasado la definición del tipo hasta el momento de la compilación, ¿cómo sabe intellisense (y cualquier otra cosa involucrada) qué tipo estoy extendiendo? ¿C = simplemente establece el valor predeterminado en el nivel superior System.Object?¿Qué estamos ampliando al crear un método de extensión genérico?

+2

¿Qué tiene esto que ver con LINQ? – BoltClock

+0

@ BoltClock'saUnicorn todo el sytnax fluido en linq se basa en métodos de extensión. –

+2

@RoyiNamir El hecho de que LINQ se base en métodos de extensión no relaciona todos los métodos de extensión LINQ. – Servy

Respuesta

1

Siendo que he retrasado la definición del tipo hasta el momento de la compilación, ¿cómo sabe Intellisense (y cualquier cosa involucrada) qué tipo estoy extendiendo? ¿C# simplemente se predetermina al nivel superior System.Object?

Los que dicen que esta es una extensión en System.Object son incorrectos. Por un lado, este método no ingresará las entradas de tipo de valor, pero sí un método de extensión definido en System.Object.

El método de extensión que ha definido es un método de extensión con parámetros genéricos. Se puede aplicar a cualquier tipo que sea válido como parámetro de tipo genérico.

Si no está pensando en los métodos de extensión de la siguiente manera, esto podría ayudarlo a comprenderlos un poco mejor. Los métodos de extensión son solo un truco que la especificación del lenguaje nos permite salirse con la suya. Los métodos de extensión son realmente solo métodos estáticos en clases estáticas que podemos llamar como si fueran métodos de instancia. Entonces

static class Foo { 
    public static void M(this object obj) { } 
} 

es solo un método estático en una clase estática. Se le podría llamar así:

Foo.M(obj); 

pero podemos decir que es como si fuera un método de instancia:

obj.M(); 

Por lo tanto, cuando se tiene un método de extensión genérica, parar por un minuto y pensar en ello como un método estático en una clase estática

static class Foo { 
    public static void M<T>(this T obj) { } 
} 

se le puede llamar así:

object obj; 
Foo.M(obj); 

o se le puede llamar así:

obj.M(); 

No hay diferencia con el compilador de la que se escribe.

Por lo tanto, ahora lo está pensando como un método genérico habitual. Pero seguramente cuando lo piense desde esta perspectiva, comprenderá que el compilador le permitirá invocar este método en cualquier tipo que sea válido como parámetro de tipo genérico. Y así, ahora comprende por qué puede considerarse como un método de extensión en cualquier tipo que sea válido como un parámetro de tipo genérico.

+0

+1 Esa es información útil para saber. ¿Cómo es que el truco funciona? ¿Debemos suponer que esto es azúcar sintáctico? En otras palabras, ¿el compilador simplemente convierte la llamada de 'obj.M()' a 'Foo.M (obj)'? –

+1

Sí, es solo azúcar sintáctico. Ver 7.6.5.2 de la especificación del lenguaje. En particular, la afirmación "la llamada al método se procesa como una invocación de método estático" se realiza en esa sección. – jason

+0

@jason 95% de información sobre azúcares séticos y 5% sobre '¿Qué estamos ampliando? Proporcione ** pruebas ** de que no estamos ampliando el sistema. Objeto. –

3

Sí, es System.Object a menos que agregue una restricción de tipo.

+1

@RoyiNamir: ** parámetros ** genéricos ('Print ()' puede, no restricciones ('donde T: SomeType'). –

+0

@GeorgeDuckett Quise decir que no tienes que agregar el tipo. T –

+0

Extender en objeto no es lo mismo que extender en todos los tipos todos los parámetros de tipo genéricos válidos. No es una extensión de 'objeto'. – jason

Cuestiones relacionadas