Pergunta

Eu tenho trabalhado com provedores recentemente, e me deparei com uma situação interessante em que queria ter uma classe abstrata que tivesse um método estático abstrato.Eu li alguns posts sobre o assunto e até fazia sentido, mas há uma explicação clara e agradável?

Foi útil?

Solução

Métodos estáticos não são instanciado como tal, eles estão disponíveis apenas sem uma referência de objeto.

Uma chamada para um método estático é feita através do nome da classe, não através de uma referência de 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 o 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ê ligar para B.Test, assim:

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

Então 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, pois foi a classe A que a definiu, e não para B.Test, mesmo que você possa escrever o código dessa forma.

Se você tinha tipos de classe, como no Delphi, onde você pode fazer uma variável referente a um tipo e não a um objeto, você 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, chamadas estáticas não são -virtual em .NET.

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

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

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

Outras dicas

Os métodos estáticos não podem ser herdados ou substituídos e é por isso que 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 filha, precisará usar seu 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 ver 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 possuem corpo, portanto não podem ser chamados.

Outro entrevistado (McDowell) disse que o polimorfismo só funciona para instâncias de objetos.Isso deve ser qualificado;existem linguagens que tratam classes como instâncias do tipo "Classe" ou "Metaclasse".Essas linguagens suportam polimorfismo para métodos de instância e de classe (estáticos).

C#, como Java e C++ antes dele, não é essa linguagem;o static A palavra-chave é usada explicitamente para denotar que o método é vinculado estaticamente em vez de dinâmico/virtual.

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

Aqui está uma situação em que definitivamente há 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 métodos estáticos (no delphi), é um pouco feio, mas funciona muito bem 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, assim podemos instanciar apenas o que é necessário, ao invés de ter todas as classes instanciadas apenas para buscar os objetos disponíveis.

Este foi um exemplo simples, mas a aplicação em si é uma aplicação 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, isso é muito mais fácil de manter do que ter um aplicativo de servidor diferente para cada cliente.

Espero que o exemplo tenha sido claro.

Os métodos abstratos são implicitamente virtuais.Os métodos abstratos requerem uma instância, mas os métodos estáticos não possuem uma instância.Portanto, você pode ter um método estático em uma classe abstrata, mas não pode ser estático abstrato (ou estático abstrato).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top