una - porque usar interfaces c#




¿Por qué no puedo tener métodos estáticos abstractos en C#? (5)

Aquí hay una situación en la que definitivamente hay una necesidad de herencia para los 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"?

Últimamente he estado trabajando con providers , 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 ​​tuvo sentido, pero ¿hay alguna explicación clara y agradable?


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 de lo que se necesita, en lugar de tener todas las clases instanciadas solo para buscar los objetos disponibles.

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

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

Espero que el ejemplo sea claro.


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

Suponga que, por un momento, podría 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 devuelto? Es bastante fácil ver que sin crear instancias de objetos, la herencia es bastante difícil. Los métodos abstractos sin herencia son solo métodos que no tienen cuerpo, por lo que no se pueden llamar.


Los métodos estáticos no se instancian como tales, solo 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 del 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 puede ver, la llamada se realiza a A.Test, porque fue la clase A la que lo definió, y no a B.Test, aunque puede escribir el código de esa manera.

Si tuviera tipos de clase , como en Delphi, donde puede hacer una variable que se refiera a un tipo y no a un objeto, tendría más uso para métodos estáticos virtuales y, por lo tanto, abstractos (y también constructores), pero no están disponibles y así, las llamadas estáticas no son virtuales 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 está utilizando una variable que, en tiempo de ejecución, puede contener muchos tipos diferentes de objetos, y por lo tanto desea llamar al método correcto para el objeto actual que tiene en la variable. Con los métodos estáticos, debe pasar por un nombre de clase de todos modos, por lo que el método exacto para llamar se conoce en el momento de la compilación porque no puede y no cambiará.

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


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







language-design