Pregunta

he estado trabajando con proveedores bastante últimamente, y me encontré con una situación interesante en la que quería tener una clase abstracta que tuviera un método estático abstracto.Leí algunas publicaciones sobre el tema y tenía sentido, pero ¿hay una explicación clara y agradable?

¿Fue útil?

Solución

Los métodos estáticos no instanciado como tal, simplemente están disponibles sin una referencia de objeto.

Una llamada a un método estático se realiza a través del nombre de la clase, no a través de una referencia de objeto, y el código de Lenguaje Intermedio (IL) para llamarlo llamará al método abstracto a través del nombre de la clase que lo definió, no necesariamente el nombre de la clase que usaste.

Déjame mostrarte un ejemplo.

Con el siguiente código:

public class A
{
    public static void Test()
    {
    }
}

public class B : A
{
}

Si llamas a B.Test, así:

class Program
{
    static void Main(string[] args)
    {
        B.Test();
    }
}

Entonces el código real dentro del método Main es el siguiente:

.entrypoint
.maxstack 8
L0000: nop 
L0001: call void ConsoleApplication1.A::Test()
L0006: nop 
L0007: ret 

Como puedes ver, la llamada se realiza a A.Test, porque fue la clase A la que lo definió, y no a B.Test, aunque puedes escribir el código de esa manera.

Si tuvieras tipos de clase, como en Delphi, donde puedes hacer que una variable haga referencia a un tipo y no a un objeto, tendrías más uso para los métodos estáticos virtuales y, por lo tanto, abstractos (y también para los constructores), pero no están disponibles y, por lo tanto, las llamadas estáticas no son -virtual en .NET.

Me doy cuenta de que los diseñadores de IL podrían permitir que el código se compile para llamar a B.Test y resolver la llamada en tiempo de ejecución, pero aún así no sería virtual, ya que aún tendría que escribir algún tipo de nombre de clase allí.

Los métodos virtuales, y por lo tanto los abstractos, solo son útiles cuando usas una variable que, en tiempo de ejecución, puede contener muchos tipos diferentes de objetos y, por lo tanto, deseas llamar al método correcto para el objeto actual que tienes en la variable.Con los métodos estáticos, necesita pasar por un nombre de clase de todos modos, por lo que el método exacto a llamar se conoce en el momento de la compilación porque no puede cambiar ni cambiará.

Por lo tanto, los métodos estáticos virtuales/abstractos no están disponibles en .NET.

Otros consejos

Los métodos estáticos no se pueden heredar ni anular y es por eso que no pueden ser abstractos.Dado que los métodos estáticos se definen en el tipo, no en la instancia, de una clase, se deben llamar explícitamente en ese tipo.Entonces, cuando quieras llamar a un método en una clase secundaria, debes usar su nombre para llamarlo.Esto hace que la herencia sea irrelevante.

Supongamos que usted podría, por un momento, heredar métodos estáticos.Imagina este escenario:

public static class Base
{
    public static virtual int GetNumber() { return 5; }
}

public static class Child1 : Base
{
    public static override int GetNumber() { return 1; }
}

public static class Child2 : Base
{
    public static override int GetNumber() { return 2; }
}

Si llama a Base.GetNumber(), ¿qué método se llamaría?¿Qué valor devolvió?Es bastante fácil ver que sin crear instancias de objetos, la herencia es bastante difícil.Los métodos abstractos sin herencia son simplemente métodos que no tienen cuerpo, por lo que no se pueden llamar.

Otro encuestado (McDowell) dijo que el polimorfismo sólo funciona para instancias de objetos.Eso debería matizarse;Hay lenguajes que tratan las clases como instancias de un tipo "Clase" o "Metaclase".Estos lenguajes admiten polimorfismo tanto para métodos de instancia como de clase (estáticos).

C#, como Java y C++ antes, no es ese lenguaje;el static La palabra clave se usa explícitamente para indicar que el método está vinculado estáticamente en lugar de dinámico/virtual.

Para complementar las explicaciones anteriores, las llamadas a métodos estáticos están vinculadas a un método específico en tiempo de compilación, lo que más bien descarta el comportamiento polimórfico.

Aquí hay una situación en la que definitivamente existe la necesidad de herencia para campos y métodos estáticos:

abstract class Animal
{
  protected static string[] legs;

  static Animal() {
    legs=new string[0];
  }

  public static void printLegs()
  {
    foreach (string leg in legs) {
      print(leg);
    }
  }
}


class Human: Animal
{
  static Human() {
    legs=new string[] {"left leg", "right leg"};
  }
}


class Dog: Animal
{
  static Dog() {
    legs=new string[] {"left foreleg", "right foreleg", "left hindleg", "right hindleg"};
  }
}


public static void main() {
  Dog.printLegs();
  Human.printLegs();
}


//what is the output?
//does each subclass get its own copy of the array "legs"?

De hecho, anulamos los métodos estáticos (en Delphi), es un poco feo, pero funciona bien para nuestras necesidades.

Lo usamos para que las clases puedan tener una lista de sus objetos disponibles sin la instancia de clase, por ejemplo, tenemos un método que se ve así:

class function AvailableObjects: string; override;
begin
  Result := 'Object1, Object2';
end; 

Es feo pero necesario, de esta manera podemos crear instancias solo de lo que se necesita, en lugar de crear instancias de todas las clases solo para buscar los objetos disponibles.

Este fue un ejemplo simple, pero la aplicación en sí es una aplicación cliente-servidor que tiene todas las clases disponibles en un solo servidor y múltiples clientes diferentes que tal vez no necesiten todo lo que tiene el servidor y nunca necesitarán una instancia de objeto.

Por tanto, esto es mucho más fácil de mantener que tener una aplicación de servidor diferente para cada cliente.

Espero que el ejemplo haya sido claro.

Los métodos abstractos son implícitamente virtuales.Los métodos abstractos requieren una instancia, pero los métodos estáticos no la tienen.Por lo tanto, puede tener un método estático en una clase abstracta, pero no puede ser estático abstracto (o abstracto estático).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top