c# generics static methods virtual

Método estático virtual C#



generics static (9)

¿Por qué es virtual estático imposible? ¿C es dependiente o simplemente no tiene ningún sentido en el mundo OO?

Sé que el concepto ya fue subrayado, pero no encontré una respuesta simple a la pregunta anterior.


Chicos que dicen que no tiene sentido en los métodos virtuales estáticos. Si no entiende cómo esto podría ser posible, no significa que sea imposible. ¡Hay idiomas que permiten esto! Mira a Delphi, por ejemplo.


En .NET, el envío de métodos virtuales se realiza (más o menos) mirando el tipo real de un objeto cuando se llama al método en tiempo de ejecución, y buscando el método más predominante del vtable de la clase. Cuando se llama a una clase estática, no hay instancia de objeto para verificar, y por lo tanto no hay vtable para hacer la búsqueda.


Eric Lippert tiene una publicación en el blog sobre esto, y como de costumbre con sus publicaciones, cubre el tema con gran profundidad:

http://blogs.msdn.com/b/ericlippert/archive/2007/06/14/calling-static-methods-on-type-parameters-is-illegal-part-one.aspx

"Virtual" y "estático" son opuestos! "Virtual" significa "determinar el método que se debe invocar en función de la información del tipo de tiempo de ejecución" y "estático" significa "determinar el método que se invocará únicamente en función del análisis estático en tiempo de compilación"


La contradicción entre "estático" y "virtual" es solo un problema. Si se reemplazara "estático" por "nivel de clase", como en muchos otros idiomas, nadie tendría los ojos vendados.

Lástima que la elección de palabras hizo que c # se paralizara a este respecto. Todavía es posible llamar al método Type.InvokeMember para simular una llamada a un método virtual de nivel de clase. Solo tiene que pasar el nombre del método como una cadena. Sin verificación de tiempo de compilación, sin tipeo fuerte y sin control, las subclases implementan el método.

Alguna belleza Delphi:

type TFormClass = class of TForm; var formClass: TFormClass; myForm: TForm; begin ... formClass = GetAnyFormClassYouWouldLike; myForm = formClass.Create(nil); myForm.Show; end


Para resumir todas las opciones presentadas:

  • Esto no es parte de C # porque en él, static significa "no ligado a nada en tiempo de ejecución" como lo ha hecho desde C (y tal vez antes). static entidades static están vinculadas al tipo declarante (por lo tanto, pueden acceder a sus otras entidades static ), pero solo en tiempo de compilación.

    • Esto es posible en otros idiomas en los que un equivalente static (si es necesario) significa "vinculado a un objeto de tipo en tiempo de ejecución" . Los ejemplos incluyen Delphi, Python, PHP.
  • Esto se puede emular de varias maneras que se pueden clasificar como:

    1. Utilizar enlace de tiempo de ejecución
      • Métodos estáticos con un objeto singleton o similar
      • Método virtual que devuelve lo mismo para todas las instancias
        • Redefinido en un tipo derivado para devolver un resultado diferente (constante o derivado de miembros estáticos del tipo de redefinición)
        • Recupera el objeto tipo de la instancia
    2. Use encuadernación en tiempo de compilación
      • Utilice una plantilla que modifique el código para cada tipo derivado para acceder a las entidades con el mismo nombre de ese tipo, por ejemplo, con el CRTP.

Sí, es posible.

El caso de uso más buscado para eso es tener fábricas que puedan ser "anuladas"

Para hacer esto, tendrá que confiar en los parámetros de tipo genérico usando el polimorfismo de F unido .

Ejemplo 1 Tomemos un ejemplo de fábrica:

class A: { public static A Create(int number) { return ... ;} } class B: A { /* How to override the static Create method to return B? */}

También quiere que createB sea ​​accesible y devuelva objetos B en la clase B. O bien, podría querer que las funciones estáticas de A sean una biblioteca que deba ser extensible por B. Solución:

class A<T> where T: A<T> { public static T Create(int number) { return ...; } } class B: A<B> { /* no create function */ } B theb = B.Create(2); // Perfectly fine. A thea = A.Create(0); // Here as well

Ejemplo 2 (avanzado): definamos una función estática para multiplicar matrices de valores.

public abstract class Value<T> where T : Value<T> { //This method is static but by subclassing T we can use virtual methods. public static Matrix<T> MultiplyMatrix(Matrix<T> m1, Matrix<T> m2) { return // Code to multiply two matrices using add and multiply; } public abstract T multiply(T other); public abstract T add(T other); public abstract T opposed(); public T minus(T other) { return this.add(other.opposed()); } } // Abstract override public abstract class Number<T> : Value<T> where T: Number<T> { protected double real; /// Note: The use of MultiplyMatrix returns a Matrix of Number here. public Matrix<T> timesVector(List<T> vector) { return MultiplyMatrix(new Matrix<T>() {this as T}, new Matrix<T>(vector)); } } public class ComplexNumber : Number<ComplexNumber> { protected double imag; /// Note: The use of MultiplyMatrix returns a Matrix of ComplexNumber here. }

Ahora también puede usar el método estático MultiplyMatrix para devolver una matriz de números complejos directamente desde ComplexNumber

Matrix<ComplexNumber> result = ComplexNumber.MultiplyMatrix(matrix1, matrix2);


Si bien técnicamente no es posible definir un método virtual estático , por todas las razones ya señaladas aquí, puede lograr funcionalmente lo que creo que intenta usar métodos de extensión C #.

Desde MSDN:

Los métodos de extensión le permiten "agregar" métodos a tipos existentes sin crear un nuevo tipo derivado, recompilar o modificar el tipo original.

Consulte los Métodos de extensión de C # (Guía de programación de C #) para obtener más detalles.


Voy a ser quien diga que no. Lo que describes no es técnicamente parte del lenguaje. Lo siento. Pero es posible simularlo dentro del lenguaje.

Consideremos lo que está pidiendo: quiere una colección de métodos que no están adjuntos a ningún objeto en particular que todos puedan ser fácilmente llamables y reemplazables en tiempo de ejecución o tiempo de compilación.

Para mí, eso suena como lo que realmente quieres es un objeto singleton con métodos delegados.

Vamos a armar un ejemplo:

public interface ICurrencyWriter { string Write(int i); string Write(float f); } public class DelegatedCurrencyWriter : ICurrencyWriter { public DelegatedCurrencyWriter() { IntWriter = i => i.ToString(); FloatWriter = f => f.ToString(); } public string Write(int i) { return IntWriter(i); } public string Write(float f) { return FloatWriter(f); } public Func<int, string> IntWriter { get; set; } public Func<float, string> FloatWriter { get; set; } } public class SingletonCurrencyWriter { public static DelegatedCurrencyWriter Writer { get { if (_writer == null) _writer = new DelegatedCurrencyWriter(); return _writer; } } }

en uso:

Console.WriteLine(SingletonCurrencyWriter.Writer.Write(400.0f); // 400.0 SingletonCurrencyWriter.Writer.FloatWriter = f => String.Format("{0} bucks and {1} little pennies.", (int)f, (int)(f * 100)); Console.WriteLine(SingletonCurrencyWriter.Writer.Write(400.0f); // 400 bucks and 0 little pennies

Dado todo esto, ahora tenemos una clase singleton que escribe valores de moneda y puedo cambiar el comportamiento de la misma. Básicamente, he definido la convención de comportamiento en tiempo de compilación y ahora puedo cambiar el comportamiento en el tiempo de compilación (en el constructor) o en el tiempo de ejecución, que es, creo que el efecto que intentas obtener. Si desea heredar el comportamiento, puede hacerlo mediante la implementación de un encadenamiento inverso (es decir, haga que el nuevo método llame al anterior).

Dicho esto, no recomiendo especialmente el código de ejemplo anterior. Por un lado, no es seguro para subprocesos y realmente no hay mucho en el lugar para mantener la vida sana. La dependencia global de este tipo de estructura significa inestabilidad global. Esta es una de las muchas maneras en que el comportamiento cambiante se implementó en los oscuros días oscuros de C: las estructuras de los indicadores de función, y en este caso una única estructura global.


virtual significa que el método llamado se elegirá en tiempo de ejecución, dependiendo del tipo dinámico del objeto. static significa que no es necesario ningún objeto para llamar al método.

¿Cómo propone hacer ambas cosas con el mismo método?