¿Por qué se requiere la palabra clave ‘this’ para llamar a un método de extensión desde dentro de la clase extendida?

Creé un método de extensión para una ASP.NET MVC ViewPage, por ejemplo:

public static class ViewExtensions { public static string Method(this ViewPage page) where T : class { return "something"; } } 

Cuando ViewPage este método desde una Vista (derivada de ViewPage ), ViewPage el error ” CS0103: El nombre ‘Método’ no existe en el contexto actual ” a menos que use la palabra clave this para llamarlo:

     

¿Por qué se requiere this palabra clave? ¿O funciona sin él, pero me falta algo?

(Creo que debe haber un duplicado de esta pregunta, pero no pude encontrar uno)

Actualización :

Como dice Ben Robinson , la syntax para llamar a los métodos de extensión es solo azúcar comstackdor. Entonces, ¿por qué el comstackdor no puede verificar automáticamente los métodos de extensión de los tipos básicos del tipo actual sin requerir esta palabra clave?

Un par de puntos:

En primer lugar, la característica propuesta (implícita “this.” En una llamada al método de extensión) es innecesaria . Los métodos de extensión eran necesarios para que las consultas de consulta LINQ funcionaran como queríamos; el receptor siempre se indica en la consulta, por lo que no es necesario respaldar implícitamente esto para hacer que LINQ funcione.

En segundo lugar, la característica funciona en contra del diseño más general de los métodos de extensión: es decir, que los métodos de extensión le permiten extender un tipo que no puede extender usted mismo , ya sea porque es una interfaz y no conoce la implementación, o porque lo hace conocer la implementación pero no tiene el código fuente.

Si se encuentra en el escenario donde está utilizando un método de extensión para un tipo dentro de ese tipo, entonces tiene acceso al código fuente. ¿Por qué estás usando un método de extensión en primer lugar, entonces? Puede escribir un método de instancia usted mismo si tiene acceso al código fuente del tipo extendido, ¡y luego no tiene que usar un método de extensión en absoluto! Su implementación puede aprovechar el acceso al estado privado del objeto, que los métodos de extensión no pueden.

Facilitar el uso de métodos de extensión desde un tipo al que tenga acceso es alentar el uso de métodos de extensión sobre métodos de instancia. Los métodos de extensión son geniales, pero generalmente es mejor usar un método de instancia si tiene uno.

Dados esos dos puntos, la carga ya no recae en el diseñador del lenguaje para explicar por qué la característica no existe. Ahora depende de usted explicar por qué debería . Las características tienen costos enormes asociados con ellos. Esta característica no es necesaria y funciona en contra de los objectives de diseño establecidos de los métodos de extensión; ¿Por qué deberíamos asumir el costo de implementarlo? Explique qué escenario importante e importante es habilitado por esta característica y consideraremos implementarlo en el futuro. No veo ningún escenario convincente e importante que lo justifique, pero quizás hay uno que me he perdido.

Sin él, el comstackdor simplemente lo ve como un método estático en una clase estática que toma la página como su primer parámetro. es decir

 // without 'this' string s = ViewExtensions.Method(page); 

vs.

 // with 'this' string s = page.Method(); 

En los métodos de instancia, ‘esto’ se pasa implícitamente a cada método de forma transparente, para que pueda acceder a todos los miembros que proporciona.

Los métodos de extensión son estáticos. Al llamar a Method() lugar de this.Method() o Method(this) , no le está diciendo al comstackdor qué pasar al método.

Podrías decir ‘¿por qué no se da cuenta de lo que es el objeto que llama y lo pasa como un parámetro?’

La respuesta es que los métodos de extensión son estáticos y se pueden llamar desde un contexto estático, donde no hay ‘esto’.

Supongo que podrían verificarlo durante la comstackción, pero para ser honesto, probablemente sea mucho trabajo por muy poco beneficio. Y para ser honesto, veo poco beneficio en quitar algo de lo explícito de las llamadas al método de extensión. El hecho de que puedan confundirse con métodos de ejemplo significa que a veces pueden ser poco intuitivos (por ejemplo, no se lanzan NullReferenceExceptions). A veces pienso que deberían haber introducido un nuevo operador de estilo ‘pipe-forward’ para los métodos de extensión.

Es importante tener en cuenta que existen diferencias entre los métodos de extensión y los métodos regulares. Creo que acabas de encontrarte con uno de ellos.

Le daré un ejemplo de otra diferencia: es bastante fácil llamar a un método de extensión en una referencia de objeto null . Afortunadamente, esto es mucho más difícil de hacer con métodos regulares. (Pero se puede hacer. IIRC, Jon Skeet demostró cómo hacer esto manipulando el código CIL).

 static void ExtensionMethod(this object obj) { ... } object nullObj = null; nullObj.ExtensionMethod(); // will succeed without a NullReferenceException! 

Habiendo dicho this , estoy de acuerdo en que parece poco logico que this requiera llamar al metodo de extension. Después de todo, un método de extensión idealmente debería “sentir” y comportarse como uno normal.

Pero, en realidad, los métodos de extensión se asemejan más al azúcar sintáctico añadido al idioma existente que a una característica principal temprana que se adapta muy bien al lenguaje en todos los aspectos.

Porque el método de extensión no existe con la clase ViewPage. Necesitas decirle al comstackdor cómo estás llamando el método de extensión. Recuerde esto. this.Method() es solo el comstackdor de azúcar para ViewExtensions.Method(this) . Es la misma manera que no puede simplemente llamar a un método de extensión en el medio de cualquier clase por el nombre del método.

Estoy trabajando en una API fluida y encontré el mismo problema. Aunque tengo acceso a la clase que estoy ampliando, aún quería que la lógica de cada uno de los métodos fluidos se encuentre en sus propios archivos. La palabra clave “this” era muy poco intuitiva, los usuarios seguían pensando que faltaba el método. Lo que hice fue convertir a mi clase en una clase parcial que implementó los métodos que necesitaba en lugar de usar métodos de extensión. No vi mención de parciales en las respuestas. Si tiene esta pregunta, los parciales podrían ser una mejor opción.