He creado un método de extensión para ASP.NET MVC ViewPage, por ejemplo:
public static class ViewExtensions
{
public static string Method<T>(this ViewPage<T> page) where T : class
{
return "something";
}
}
Al llamar a este método desde una Vista (derivada de ViewPage
), aparece el error " CS0103: El nombre 'Método' no existe en el contexto actual " a menos que use la this
palabra clave para llamarlo:
<%: Method() %> <!-- gives error CS0103 -->
<%: this.Method() %> <!-- works -->
¿Por qué se this
requiere la 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 sintaxis para llamar a los métodos de extensión es simplemente azúcar de compilación. Entonces, ¿por qué el compilador no puede verificar automáticamente los métodos de extensión de los tipos base del tipo actual sin requerir la palabra clave this?
this
palabra clave), pero estoy preguntando por quéthis
se requiere la palabra clave. Actualicé mi pregunta.Respuestas:
Un par de puntos:
En primer lugar, la función propuesta (implícita "esto" en una llamada al método de extensión) es innecesaria . Los métodos de extensión eran necesarios para que las comprensiones de consultas LINQ funcionaran como queríamos; el receptor siempre se indica en la consulta, por lo que no es necesario admitir esto implícitamente para que LINQ funcione.
En segundo lugar, la función 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 la conoce. Conozca la implementación pero no tenga el código fuente.
Si usted está en el escenario en el que se utiliza un método de extensión para un tipo dentro de ese tipo , entonces no tiene acceso al código fuente. Entonces, ¿por qué estás usando un método de extensión? Puede escribir un método de instancia usted mismo si tiene acceso al código fuente del tipo extendido, ¡y entonces no tiene que usar ningún método de extensión! Entonces, su implementación puede aprovechar el acceso al estado privado del objeto, lo que los métodos de extensión no pueden.
Facilitar el uso de métodos de extensión desde dentro de un tipo al que tiene acceso es fomentar el uso de métodos de extensión sobre los 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 sobre el diseñador del lenguaje para explicar por qué no existe la función . Ahora le toca a usted explicar por qué debería hacerlo . Las características tienen enormes costos asociados con ellas. Esta característica no es necesaria y funciona en contra de los objetivos de diseño establecidos de los métodos de extensión; ¿Por qué deberíamos asumir el costo de implementarlo? Explique qué escenario importante y convincente permite esta función y consideraremos implementarla en el futuro. No veo ningún escenario importante y convincente que lo justifique, pero tal vez haya uno que me haya perdido.
fuente
this
se requiere. 2: ¿Por qué llamo a un método de extensión desde el tipo extendido? En el ejemplo dado, estoy agregando algunos métodos de conveniencia a la clase base (ViewPage) y lo estoy llamando desde clases derivadas. Esto elimina la necesidad de crear una clase base común para todas mis vistas. Por cierto: estoy de acuerdo en que usar un método de extensión desde dentro del tipo extendido es incómodo, pero nuevamente vea el ejemplo con MVC ViewPage.ICrossProductable
y define un método de extensión en esa interfaz llamadaGetProduct
. Ejemplo muy simple, pero a menudo lo encuentro útil. Sin embargo, no es el mejor enfoque en todos los casos.Sin él, el compilador 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();
fuente
En los métodos de instancia, 'this' se pasa implícitamente a cada método de forma transparente, por lo que puede acceder a todos los miembros que proporciona.
Los métodos de extensión son estáticos. Al llamar en
Method()
lugar dethis.Method()
oMethod(this)
, no le está diciendo al compilador qué pasar al método.Podría decir '¿por qué no se da cuenta de cuál es el objeto de llamada 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 comprobarlo durante la compilación, pero para ser honesto, probablemente sea mucho trabajo por muy poco beneficio. Y, para ser honesto, veo pocos beneficios en eliminar parte de la explícitaidad de las llamadas al método de extensión. El hecho de que se puedan confundir, por ejemplo, con métodos significa que a veces pueden ser bastante poco intuitivos (por ejemplo, NullReferenceExceptions no arroja). A veces pienso que deberían haber introducido un nuevo operador de estilo 'pipe-forward' para métodos de extensión.
fuente
Es importante tener en cuenta que existen diferencias entre los métodos de extensión y los métodos regulares. Creo que te has cruzado 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
null
referencia de objeto. Afortunadamente, esto es mucho más difícil de hacer con los métodos habituales. (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!
Dicho esto, estoy de acuerdo en que parece un poco poco lógico que
this
se requiera llamar al método de extensión. Después de todo, un método de extensión idealmente debería "sentirse" y comportarse como uno normal.Pero en realidad, los métodos de extensión son más como azúcar sintáctico agregado sobre el lenguaje existente que como una característica básica temprana que encaja perfectamente en el lenguaje en todos los aspectos.
fuente
null
? Podría ser casi cualquier tipo de referencia, ¿cómo sabe qué métodos están disponiblesnull
?String
lógicamente se comportan como valores, y podrían tener un valor predeterminado sensible cuando son nulos (por ejemplo, .net podría considerar consistentemente una referencia nula de tipo estáticostring
como una cadena vacía, en lugar de hacerlo solo esporádicamente). Tener que usar métodos estáticos para cosas como estaif (!String.IsNullOrEmpty(stringVar))
es simplemente espantoso.Porque el método de extensión no existe con la clase ViewPage. Necesita decirle al compilador en qué está llamando al método de extensión. Recuerde que
this.Method()
es solo azúcar de compilación paraViewExtensions.Method(this)
. Es de la misma manera que no puedes simplemente llamar a un método de extensión dentro de cualquier clase por el nombre del método.fuente
this
palabra clave?Estoy trabajando en una API fluida y encontré el mismo problema. Aunque tengo acceso a la clase que estoy ampliando, todavía quería que la lógica de cada uno de los métodos fluidos estuviera 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 mi clase en una clase parcial que implementó los métodos que necesitaba en lugar de usar métodos de extensión. No vi ninguna mención de parciales en las respuestas. Si tiene esta pregunta, los parciales podrían ser una mejor opción.
fuente