2010-10-11 25 views
10

¿Puede alguien explicarme por qué a continuación la tercera invocación de DoSomething no es válida? (Mensaje de error es "El nombre 'HacerAlgo' no existe en el contexto actual")¿Por qué no puede invocar los métodos de extensión directamente?

public class A { } 
public class B : A 
{ 
    public void WhyNotDirect() 
    { 
     var a = new A(); 
     a.DoSomething(); // OK 
     this.DoSomething(); // OK 
     DoSomething(); // ?? Why Not 
    } 
} 
public static class A_Ext 
{ 
    public static void DoSomething(this A a) 
    { 
     Console.WriteLine("OK"); 
    } 
} 

Respuesta

2

Los métodos de extensión siguen siendo métodos estáticos, no llamadas a instancias verdaderas. Para que esto funcione, usted necesitaría contexto específico utilizando la sintaxis de método de instancia (de Extension Methods (C# Programming Guide))

en su código se invoca el método de extensión con la sintaxis método de instancia. Sin embargo, el lenguaje intermedio (IL) generado por el compilador traduce su código en una llamada en el método estático. Por lo tanto, el principio de encapsulación no se está violando realmente . De hecho, los métodos de extensión no pueden acceder a las variables privadas en el tipo que están extendiendo .

Así, mientras que normalmente, ambos trabajarían sintaxis, el segundo es sin contexto explícito, y parecería que el IL generado no puede obtener el contexto de manera implícita.

+0

Esto me da la mejor idea hasta ahora, creo. Entonces, básicamente, porque podría estar invocando un método que podría tener el mismo nombre y firma en una clase base y en la clase de extensión, ¿podría no saber cuál elegir en ese caso? Eso tendria sentido para mi. ¿Es eso correcto? –

+1

@My Other Me: mientras lo leía, no era tanto un problema de ambigüedad como un problema de firma. En el código IL, el método de extensión todavía se considera estático. Sin embargo, el compilador crea un código de traducción que es específico del contexto con respecto a una instancia. Parece que usar 'this' crea ese contexto y sin un especificador de instancia, el compilador es libre de adivinar la" mejor coincidencia ", que sería la clase base sin la extensión. –

+2

En última instancia, esto es simplemente una elección del compilador: la consideración de un 'this' implícito cuando se resuelven métodos depende enteramente del compilador. Nada que ver con IL. El compilador podría elegir implementar 'this.SomeExtensionMethod()' y 'SomeExtensionMethod()' de forma idéntica, haciendo una llamada estática a 'SomeExtensionMethod (this)' –

3

Debido DoSomething toma un parámetro.

DoSomething(a) sería legal.

Editar

leí la pregunta un poco mal aquí.

Como su llamada es un método estático normal, y no un método de extensión, necesita advertir con el nombre de la clase.

Así que A_Ext.DoSomething(a); funcionará.

Si lo llamas como un método estático normal, se aplican las mismas reglas.

Su segunda variante funciona porque B entra en A, y por lo tanto usted todavía termina llamándola como un método de extensión, pero la tercera no.

disculpa por la primera versión anterior que no trabajo. Lo dejo para mantener el comentario relevante.

+1

No, no lo es. Mismo error. –

+0

Gracias: Editar notado. –

2

DoSomething requiere una instancia de A para hacer cualquier cosa, y sin un calificador, el compilador no puede ver qué DoSomething necesita invocar. No sabe marcar A_Ext para su método a menos que lo califique con this.

+2

¿Por qué no puede llegar a esa conclusión por sí mismo? "Encuentra" el método de extensión cuando hago referencia a "esto". a través de la jerarquía de clases ¿verdad? Seguramente debería ser posible hacer esto sin el "esto". ¿aspecto? –

+3

Creo que se trata más de un comportamiento predecible. Es mejor tener un calificador y hacer que el compilador sepa tus intenciones para que lo adivine por ti. – mgbowen

+2

+1 para la respuesta y el comentario. C# está diseñado para errar por el lado de la calificación explícita en lugar de hacer que el compilador adivine a qué te refieres, incluso cuando pueda parecer una base perfectamente razonable para una suposición precisa. Visite el blog de Eric Lippert (http://blogs.msdn.com/b/ericlippert/) para ver muchos, muchos ejemplos de este proceso de toma de decisiones. –

5

Los métodos de extensión pueden ser invocados como otros métodos estáticos.

Cámbielo a A_Ext.DoSomething(this).

Si está preguntando por qué no se invoca implícitamente en this, la respuesta es que esa es la forma en que se escribió la especificación. Supongo que la razón es que llamarlo sin un calificador sería demasiado engañoso.

+1

No le preocupa resolver la llamada. Usar 'this' ya lo ha hecho por él. Él quiere entender por qué uno funciona cuando el otro no. –

+0

Gracias. Sé cómo puedo obligarlo a invocar (esto), pero estoy tratando de entender realmente por qué es necesario. –

+0

"Porque esa es la forma en que se escribió la especificación" Exactamente, vea @MarcGravell comentar la respuesta aceptada. La mayoría de las demás respuestas reclaman erróneamente limitaciones técnicas. Imo, debería permitirse, no hay ambigüedad, usa C++ si quieres el tedio de lo explícito. – crokusek

Cuestiones relacionadas