c# - exemplo - tipos de dados abstratos java




Por que não posso ter métodos estáticos abstratos em c#? (5)

Ultimamente, tenho trabalhado com providers e me deparei com uma situação interessante em que queria ter uma classe abstrata que tivesse um método estático abstrato. Li alguns posts sobre o assunto, e isso meio que fazia sentido, mas há uma boa explicação clara?


Aqui está uma situação em que há definitivamente uma necessidade de herança para campos e 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"?

Na verdade, substituímos os métodos estáticos (no delphi), é um pouco feio, mas funciona perfeitamente para as nossas necessidades.

Nós o usamos para que as classes possam ter uma lista de seus objetos disponíveis sem a instância da classe; por exemplo, temos um método parecido com este:

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

É feio, mas necessário; dessa forma, podemos instanciar exatamente o que é necessário, em vez de ter todas as classes instanciadas apenas para procurar os objetos disponíveis.

Este foi um exemplo simples, mas o aplicativo em si é um aplicativo cliente-servidor que possui todas as classes disponíveis em apenas um servidor e vários clientes diferentes que podem não precisar de tudo o que o servidor possui e nunca precisarão de uma instância de objeto.

Portanto, é muito mais fácil manter isso do que ter um aplicativo de servidor diferente para cada cliente.

Espero que o exemplo seja claro.


Os métodos estáticos não podem ser herdados ou substituídos, e é por isso que eles não podem ser abstratos. Como os métodos estáticos são definidos no tipo, e não na instância, de uma classe, eles devem ser chamados explicitamente nesse tipo. Portanto, quando você quiser chamar um método em uma classe filho, precisará usar o nome para chamá-lo. Isso torna a herança irrelevante.

Suponha que você possa, por um momento, herdar métodos estáticos. Imagine este cenário:

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; }
}

Se você chamar Base.GetNumber (), qual método seria chamado? Qual valor retornou? É muito fácil perceber que, sem criar instâncias de objetos, a herança é bastante difícil. Métodos abstratos sem herança são apenas métodos que não têm um corpo, portanto não podem ser chamados.


Os métodos estáticos não são instanciados como tal, apenas estão disponíveis sem uma referência a objeto.

Uma chamada para um método estático é feita através do nome da classe, não através de uma referência a objeto, e o código de Linguagem Intermediária (IL) para chamá-lo chamará o método abstrato através do nome da classe que a definiu, não necessariamente o nome de a classe que você usou.

Deixe-me mostrar um exemplo.

Com o seguinte código:

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

public class B : A
{
}

Se você chamar B.Test, assim:

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

Em seguida, o código real dentro do método Main é o seguinte:

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

Como você pode ver, a chamada é feita para A.Test, porque foi a classe A que a definiu, e não para B.Test, mesmo que você possa escrever o código dessa maneira.

Se você tivesse tipos de classe , como no Delphi, onde você pode criar uma variável referente a um tipo e não a um objeto, teria mais uso para métodos estáticos virtuais e, portanto, abstratos (e também construtores), mas eles não estão disponíveis e portanto, as chamadas estáticas não são virtuais no .NET.

Percebo que os designers de IL podem permitir que o código seja compilado para chamar B.Test e resolver a chamada em tempo de execução, mas ainda não seria virtual, pois você ainda teria que escrever algum tipo de nome de classe lá.

Métodos virtuais e, portanto, abstratos, são úteis apenas quando você está usando uma variável que, em tempo de execução, pode conter muitos tipos diferentes de objetos e, portanto, você deseja chamar o método correto para o objeto atual que você possui na variável. Com os métodos estáticos, você precisa passar pelo nome de uma classe de qualquer maneira; portanto, o método exato a ser chamado é conhecido no momento da compilação, porque não pode e não muda.

Portanto, métodos estáticos virtuais / abstratos não estão disponíveis no .NET.


Para adicionar às explicações anteriores, as chamadas de método estático são vinculadas a um método específico em tempo de compilação , que exclui o comportamento polimórfico.







language-design