Soy fanático de los métodos de extensión en C #, pero no he tenido éxito al agregar un método de extensión a una clase estática, como la consola.
Por ejemplo, si quiero agregar una extensión a la consola, llamada 'WriteBlueLine', para poder ir:
Console.WriteBlueLine("This text is blue");
Intenté esto agregando un método estático público local, con la consola como un parámetro 'esto' ... ¡pero sin dados!
public static class Helpers {
public static void WriteBlueLine(this Console c, string text)
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(text);
Console.ResetColor();
}
}
Esto no agregó un método 'WriteBlueLine' a la consola ... ¿Lo estoy haciendo mal? ¿O pedir lo imposible?
c#
static
extension-methods
Leon Bambrick
fuente
fuente
Helpers.WriteBlueLine(null, "Hi");
:)Respuestas:
No. Los métodos de extensión requieren una variable de instancia (valor) para un objeto. Sin embargo, puede escribir un contenedor estático alrededor de la
ConfigurationManager
interfaz. Si implementa el reiniciador, no necesita un método de extensión ya que simplemente puede agregar el método directamente.fuente
¿Se pueden agregar extensiones estáticas a las clases en C #? No, pero puedes hacer esto:
Así es como funciona. Si bien técnicamente no puede escribir métodos de extensión estáticos, en su lugar, este código explota una laguna en los métodos de extensión. Esa laguna es que puede llamar a métodos de extensión en objetos nulos sin obtener la excepción nula (a menos que acceda a algo a través de @this).
Así que así es como usarías esto:
Ahora, ¿POR QUÉ elegí llamar al constructor predeterminado como ejemplo y Y por qué no solo devuelvo el nuevo T () en el primer fragmento de código sin hacer toda esa basura Expression? Bueno, hoy es tu día de suerte porque obtienes un 2fer. Como cualquier desarrollador avanzado de .NET sabe, el nuevo T () es lento porque genera una llamada a System.Activator que utiliza la reflexión para obtener el constructor predeterminado antes de llamarlo. ¡Maldita sea Microsoft! Sin embargo, mi código llama al constructor predeterminado del objeto directamente.
Las extensiones estáticas serían mejores que esto, pero los tiempos desesperados requieren medidas desesperadas.
fuente
XConsole
,ConsoleHelper
etc.(null as DataSet).Create();
podría serdefault(DataSet).Create();
.No es posible.
Y sí, creo que MS cometió un error aquí.
Su decisión no tiene sentido y obliga a los programadores a escribir (como se describió anteriormente) una clase de envoltura sin sentido.
Aquí hay un buen ejemplo: Intentar extender la clase de prueba estática de MS Unit Assert: Quiero 1 método Assert más
AreEqual(x1,x2)
.La única forma de hacerlo es apuntar a diferentes clases o escribir un contenedor alrededor de cientos de métodos Assert diferentes. ¿¡Por qué!?
Si se tomó la decisión de permitir extensiones de instancias, no veo ninguna razón lógica para no permitir extensiones estáticas. Los argumentos sobre seccionar bibliotecas no resisten una vez que se pueden extender las instancias.
fuente
Assert.Throws
responder a la respuesta stackoverflow.com/questions/113395/…Me topé con este hilo mientras intentaba encontrar una respuesta a la misma pregunta que tenía el OP. No encontré la respuesta que quería pero terminé haciendo esto.
Y lo uso así:
fuente
Tal vez podría agregar una clase estática con su espacio de nombres personalizado y el mismo nombre de clase:
fuente
A partir de C # 7, esto no es compatible. Sin embargo, hay discusiones sobre la integración de algo así en C # 8 y propuestas que vale la pena apoyar .
fuente
No Las definiciones de métodos de extensión requieren una instancia del tipo que está extendiendo. Es desafortunado; No estoy seguro de por qué se requiere ...
fuente
En cuanto a los métodos de extensión, los métodos de extensión en sí mismos son estáticos; pero se invocan como si fueran métodos de instancia. Como una clase estática no es instanciable, nunca tendría una instancia de la clase para invocar un método de extensión. Por esta razón, el compilador no permite que se definan métodos de extensión para clases estáticas.
Obnoxious escribió: "Como cualquier desarrollador avanzado de .NET sabe, el nuevo T () es lento porque genera una llamada a System.Activator que utiliza la reflexión para obtener el constructor predeterminado antes de llamarlo".
New () se compila con la instrucción IL "newobj" si el tipo se conoce en tiempo de compilación. Newobj toma un constructor para invocación directa. Las llamadas a System.Activator.CreateInstance () se compilan con la instrucción "call" de IL para invocar System.Activator.CreateInstance (). New () cuando se usa contra tipos genéricos dará como resultado una llamada a System.Activator.CreateInstance (). La publicación del Sr. Obnoxious no estaba clara en este punto ... y bueno, desagradable.
Este código:
produce esta IL:
fuente
No puede agregar métodos estáticos a un tipo. Solo puede agregar (pseudo-) métodos de instancia a una instancia de un tipo.
El objetivo del
this
modificador es decirle al compilador de C # que pase la instancia en el lado izquierdo.
del primer parámetro del método estático / de extensión.En el caso de agregar métodos estáticos a un tipo, no hay ninguna instancia para pasar el primer parámetro.
fuente
Traté de hacer esto con System.Environment cuando estaba aprendiendo métodos de extensión y no tuve éxito. La razón es, como otros mencionan, porque los métodos de extensión requieren una instancia de la clase.
fuente
No es posible escribir un método de extensión, sin embargo, es posible imitar el comportamiento que está solicitando.
Esto le permitirá llamar a Console.WriteBlueLine (fooText) en otras clases. Si las otras clases desean acceder a las otras funciones estáticas de la Consola, deberán ser referenciadas explícitamente a través de su espacio de nombres.
Siempre puede agregar todos los métodos a la clase de reemplazo si desea tenerlos todos en un solo lugar.
Entonces tendrías algo como
Esto proporcionaría el tipo de comportamiento que está buscando.
* Nota La consola tendrá que agregarse a través del espacio de nombres en el que la colocó.
fuente
Sí, en un sentido limitado.
Esto funciona pero la consola no lo hace porque es estática.
Esto funciona porque siempre que no esté en el mismo espacio de nombres. El problema es que debe escribir un método estático proxy para cada método que tenga System.Console. No es necesariamente algo malo, ya que puede agregar algo como esto:
o
La forma en que funciona es que conectas algo a la línea de escritura estándar. Podría ser un recuento de líneas o un filtro de palabras malas o lo que sea. Siempre que especifique la consola en su espacio de nombres, diga WebProject1 e importe el espacio de nombres Sistema, WebProject1.Console se elegirá sobre System.Console como predeterminado para esas clases en el espacio de nombres WebProject1. Entonces, este código convertirá todas las llamadas de Console.WriteLine en azul en la medida en que nunca especificó System.Console.WriteLine.
fuente
Lo siguiente fue rechazado como una edición de la respuesta de tvanfosson. Me pidieron que contribuyera como mi propia respuesta. Usé su sugerencia y terminé la implementación de un
ConfigurationManager
contenedor. En principio, simplemente...
completé la respuesta de tvanfosson.fuente
Puede usar un yeso en nulo para que funcione.
La extensión:
Tu tipo:
fuente
PUEDE hacer esto si está dispuesto a "frigirlo" un poco haciendo una variable de la clase estática y asignándola a nulo. Sin embargo, este método no estaría disponible para llamadas estáticas en la clase, por lo que no estoy seguro de cuánto uso tendría:
fuente