Pergunta

Tanto quanto eu sei que não é possível fazer o seguinte em C # 2.0

public class Father
{
    public virtual Father SomePropertyName
    {
        get
        {
            return this;
        }
    }
}

public class Child : Father
{
    public override Child SomePropertyName
    {
        get
        {
            return this;
        }
    }
}

Eu resolver o problema criando a propriedade na classe derivada como "novo", mas é claro que não é polimórfico.

public new Child SomePropertyName

Existe alguma solução em 2,0? E sobre quaisquer características em 3,5 que tratam desse assunto?

Foi útil?

Solução

Isso não é possível em qualquer linguagem .NET devido a preocupações de tipo de segurança. Em línguas tipo seguro, você deve fornecer covariância para valores de retorno, e contravariância para parâmetros. Tome este código:

class B {
    S Get();
    Set(S);
}
class D : B {
    T Get();
    Set(T);
}

Para os métodos Get, meios de covariância que T deve ser tanto S ou um tipo derivado de S. Caso contrário, se você tivesse uma referência a um objeto do tipo D armazenado em uma variável digitado B, quando você chamou B.Get() você não iria obter um representável objeto como um S volta -. Quebrar o sistema de tipo

Para os métodos Set, meios contravariance que T deve ser tanto S ou um tipo que deriva a partir de S. Caso contrário, se você tivesse uma referência a um objeto do tipo D armazenado em uma variável digitado B, quando você chamou B.Set(X), onde X era do tipo S, mas não do tipo T, D::Set(T) iria receber um objeto de um tipo que não esperava.

Em C #, houve uma decisão consciente de não permitir a alteração do tipo ao sobrecarregar propriedades, mesmo quando eles têm apenas um do par de getter / setter, porque, caso contrário, têm um comportamento muito inconsistente ( "Quer dizer, eu pode alterar o tipo de um com um getter, mas não com tanto um getter e setter por que não " -?!?. Anonymous universo alternativo Novato)

Outras dicas

Você pode re-declare (novo), mas você não pode re-declare e substituição, ao mesmo tempo (com o mesmo nome). Uma opção é usar um método protegido para esconder os detalhes - o que permite tanto polimorfismo e esconder ao mesmo tempo:

public class Father
{
    public Father SomePropertyName
    {
        get {
            return SomePropertyImpl();
        }
    }
    protected virtual Father SomePropertyImpl()
    {
        // base-class version
    }
}

public class Child : Father
{
    public new Child SomePropertyName
    {
        get
        { // since we know our local SomePropertyImpl actually returns a Child
            return (Child)SomePropertyImpl();
        }
    }
    protected override Father SomePropertyImpl()
    {
        // do something different, might return a Child
        // but typed as Father for the return
    }
}

Não, mas você pode usar os genéricos em 2 e acima:

public class MyClass<T> where T: Person
{
    public virtual T SomePropertyName
    {
        get
        {
            return  ...;
        }
    }
}

Em seguida, o pai ea criança são versões genéricas da mesma classe

A partir Wikipedia :

Na linguagem de programação C #, suporte para-tipo de retorno covariância e parâmetro Foi adicionado contravariância para delegados na versão 2.0 da linguagem. Nem covariância nem contravariance são suportados por método de substituição.

Ele não diz explicitamente nada sobre covariância de propriedades embora.

Você pode criar uma interface comum para pai e filho e retornar um tipo de interface.

No. faz C # não suporta essa idéia (que é chamado de "tipo de retorno covariância"). No entanto, pode fazer isso:

public class FatherProp
{
}

public class ChildProp: FatherProp
{
}


public class Father
{
    public virtual FatherProp SomePropertyName
    {
        get
        {
            return new FatherProp();
        }
    }
}


public class Child : Father
{
    public override FatherProp SomePropertyName
    {
        get
        {
            // override to return a derived type instead
            return new ChildProp();
        }
    }
}

i. utilização do contrato definido pela classe de base, mas retornar um tipo derivado. Fiz uma amostra mais detalhada para tornar este ponto mais claro -. Retornando "este" novamente não mudaria nada

É possível (mas confuso) para testar o objeto retornado para ele do tipo real (ou seja, "se someObject é ChildProp"), mas é melhor chamar um método virtual em que faz a coisa certa para o seu tipo.

O método de classe base virtual (neste caso, a propriedade virtual) não só tem uma implementação, mas também define um contrato: a de que uma classe filha pode fornecer uma implementação diferente de SomePropertyName se cumprir este contrato (ou seja SomePropertyName retorna um objeto do tipo "FatherProp"). Retornando um objeto do tipo "ChildProp" derivado de "FatherProp" atende a esse contrato. Mas você não pode mudar o contrato em "Child." - este contrato se aplica a todas as classes descendentes de "Pai"

Se você tomar um passo para trás e olhar para o seu projeto mais amplo, há outras construções de linguagem do C # conjunto de ferramentas que você também pode querer pensar em vez -. Genéricos, ou de interfaces

No. faz C # não suporta essa idéia (Ele é chamado "tipo de retorno covariância ").

De Wikipedia:

Na linguagem de programação C #, Suporte para o tipo de retorno covariância e parâmetro Foi adicionado contravariância para delegados na versão 2.0 da linguagem. Nem covariância nem contravariance são suportados por método de substituição.

Você pode re-declare (novo), mas você não pode voltar a declarar e substituição no mesmo tempo (com o mesmo nome). 1 opção é usar um método protegido para esconder os detalhes - isso permite que tanto polimorfismo e ocultação ao mesmo tempo:

As melhores soluções seria a de genéricos de uso:

public class MyClass<T> where T: Person
{
   public virtual T SomePropertyNameA
   {        
      get { return  ...; }    
   }
}//Then the Father and Child are generic versions of the same class

Este é o mais próximo que eu poderia vir (até agora):

    public sealed class JustFather : Father<JustFather> {}

    public class Father<T> where T : Father<T>
    { public virtual T SomePropertyName
        { get { return (T) this; }
        }
    }

    public class Child : Father<Child>
    { public override Child SomePropertyName
        { get { return  this; }
        }
    }

Sem a classe JustFather, você não poderia instanciar um Father<T> a menos que fosse algum outro tipo derivado.

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