Pergunta

Recentemente, tive um problema onde parece que eu preciso de um método 'estática abstrata'. Eu sei porque é impossível, mas como posso contornar essa limitação?

Por exemplo, eu tenho uma classe abstrata que tem uma cadeia de descrição. Uma vez que esta cadeia é comum para todos os casos, ele é marcado como estático, mas eu quero exigem que todas as classes derivado dessa classe fornecer sua própria propriedade Descrição então eu marcado como abstrato:

abstract class AbstractBase
{
    ...
    public static abstract string Description{get;}
    ...
}

Ele não irá compilar é claro. Pensei em usar as interfaces, mas as interfaces não podem conter assinaturas de métodos estáticos.

Devo fazer isso simplesmente não-estático, e sempre obter uma instância para obter essa informação classe específica?

Todas as idéias?

Foi útil?

Solução

A combinação de estático e abstrato é um pouco sem sentido, sim. A idéia por trás estática é uma necessidade não apresentar uma instância da classe, a fim de utilizar o membro em questão; no entanto, com resumo, espera-se uma instância de ser de uma classe derivada que fornece uma implementação concreta.

Eu posso ver porque você iria querer esse tipo de combinação, mas o fato é o único efeito seria negar o uso implementação de 'isto' ou quaisquer membros não-estáticos. Ou seja, a classe pai iria ditar uma restrição na implementação da classe derivada, embora não há nenhuma diferença fundamental entre chamar um resumo ou membro da 'estática abstrato' (tanto como seria necessário um exemplo concreto para descobrir o que de implementação para o uso)

Outras dicas

Você não pode.

O lugar para fazer isso é com atributos.

Por exemplo

[Name("FooClass")]
class Foo
{
}

Se você não se importa adiando para implementações de forma sensata implementar a propriedade Descrição, você pode simplesmente fazer

public abstract string ClassDescription {get; } 
// ClassDescription is more intention-revealing than Description

E a implementação de classes iria fazer algo parecido com isto:

static string classDescription="My Description for this class";
override string  ClassDescription { get { return classDescription; } }

Em seguida, suas aulas são obrigados a seguir o contrato de ter uma descrição, mas você deixá-lo para eles a fazê-lo de forma sensata. Não há nenhuma maneira de especificar uma implementação de uma forma orientada a objetos (exceto através cruéis, hacks frágeis).

No entanto, na minha mente Esta descrição é metadados classe, então eu preferiria usar o mecanismo de atributo como outros já descritos. Se você está particularmente preocupado com usos múltiplos da reflexão, criar um objeto que reflete sobre o atributo que você está preocupado com, e armazenar um dicionário entre o tipo ea descrição. Isso irá minimizar a reflexão (além de uma inspecção tipo de tempo de execução, o que não é de todo ruim). O dicionário pode ser armazenada como um membro de qualquer classe que normalmente precisa desta informação, ou, se os clientes em todo o domínio necessitam que, através de um objeto singleton ou contexto.

Se é estática, há apenas uma instância da variável, não vejo como a herança faria sentido se pudéssemos fazer o que você quer alcançar com estática vars em classes derivadas. Pessoalmente acho que você está indo muito longe para tentar evitar uma instância var.

Por que não apenas a maneira clássica?

abstract class AbstractBase
{
    protected string _Description = "I am boring abstract default value";
}

class Foo : AbstractBase {

     public Foo() {
       _Description = "I am foo!";
     }
}

Não é estática se tiver que ser chamado em uma instância.

Se você não está chamando-o em uma instância, então não há nenhum polimorfismo em jogo (ou seja ChildA.Description é completamente alheios a ChildB.Description, tanto quanto a língua está em causa).

Uma solução possível é definir um Singleton de sua classe derivada em sua classe base com a ajuda de Genéricos.

import System;

public abstract class AbstractBase<T>
    where T : AbstractBase<T>, new()
{
    private static T _instance = new T();

    public abstract string Description { get; }
    public static string GetDescription()
    {
        return _instance.Description;
    }
}

public class DerivedClass : AbstractBase<DerivedClass>
{
    public override string Description => "This is the derived Class";
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(DerivedClass.GetDescription());
        Console.ReadKey();
    }
}

O truque é dizer ao seu AbstractBase<T> alguns detalhes sobre como DerivedClass é implementado:

  • É newable com where T: new() para que ele possa criar uma instância de Singleton
  • Deriva-se com where T : AbstractBase<T> para que ele saiba que haverá uma implementação de Description

Desta forma _instance contém o campo Description que pode ser chamado no GetDescription() método estático. Isso força você a substituir Descriptionin seu DerivedClass e permite que você ligue para o seu valor com DerivedClass.GetDescription()

Você poderia fazer o método "abstrato" base lançar uma Exception, então, em seguida, um desenvolvedor é "advertiu" se ele tenta chamar esse método em uma classe criança sem substituir.

A desvantagem é que se poderia estender a classe e não usar este método. Em seguida, referem-se a outras respostas fornecidas.

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