Pergunta

Eu tenho uma classe base abstrata e quero declarar um campo ou uma propriedade que terá um valor diferente em cada classe que herda esta classe pai.

Eu quero defini-lo nos baseclass para que eu possa fazer referência a ela em um método de classe base - por exemplo substituindo ToString a dizer "Este objeto é do tipo propriedade / campo ". Eu tenho três maneiras que eu posso ver de fazer isso, mas eu queria saber - o que é o melhor ou aceite maneira de fazer isso? questão novato, desculpe.

Opção 1:
Use uma propriedade abstrata e substituí-lo nas classes herdadas. Este benefícios sejam aplicadas (você tem que substituí-lo) e é limpo. Mas, ele se sente um pouco errado para retornar um valor de código de disco em vez de encapsular um campo e é algumas linhas de código em vez de apenas. Eu também tenho a declarar um corpo de "set", mas que é menos importante (e provavelmente há uma maneira de evitar o que eu não estou ciente de).

abstract class Father
{
    abstract public int MyInt { get; set;}
}

class Son : Father
{
    public override int MyInt
    {
        get { return 1; }
        set { }
    }
}

Opção 2
Eu posso declarar um campo público (ou um campo protegido) e explicitamente substituí-lo na classe herdada. O exemplo abaixo vai me dar um aviso para usar o "novo" e eu provavelmente pode fazer isso, mas parece errado e ele quebra o polimorfismo, que foi o ponto inteiro. Não parece uma boa idéia ...

abstract class Mother
{
    public int MyInt = 0;
}

class Daughter : Mother
{
    public int MyInt = 1;
}

Opção 3
Posso usar um campo protegido e defina o valor no construtor. Isso parece bastante arrumado, mas confia em mim garantindo o construtor sempre define este e com múltiplas sobrecarregado construtores há sempre uma chance de alguns caminho de código não irá definir o valor.

abstract class Aunt
{
    protected int MyInt;
}

class Niece : Aunt
{
    public Niece()
    {
        MyInt = 1;
    }
}

É um pouco de uma questão teórica e eu acho que a resposta tem de ser a opção 1, pois é o único segura opção, mas eu estou apenas começando a lidar com C # e queria perguntar isso de pessoas com mais experiência.

Foi útil?

Solução

Das três soluções única Opção 1 é polimórfica .

Os campos por si só não pode ser substituído. Que é exatamente por isso que Opção 2 retorna o new alerta palavra-chave.

A solução para o aviso não é para anexar a “nova” palavra-chave, mas para implementar Opção 1.

Se você precisar de seu campo para ser polimórfico você precisa envolvê-la em uma propriedade.

Opção 3 é OK se você não precisa de comportamento polimórfico. Você deve se lembrar, porém, que, quando em tempo de execução a propriedade MyInt é acessado, a classe derivada não tem controle sobre o valor retornado. A classe base por si só é capaz de devolver este valor.

Isto é como uma implementação verdadeiramente polimórfico de sua propriedade pode parecer, permitindo que as classes derivadas para a controle .

abstract class Parent
{
    abstract public int MyInt { get; }
}

class Father : Parent
{
    public override int MyInt
    {
        get { /* Apply formula "X" and return a value */ }
    }
}

class Mother : Parent
{
    public override int MyInt
    {
        get { /* Apply formula "Y" and return a value */ }
    }
}

Outras dicas

A opção 2 é um non-starter - você não pode substituir campos, você só pode hide -los

.

Pessoalmente, eu iria para a opção 1 de cada vez. Eu tento manter campos privada em todos os momentos. Isto é, se você realmente precisa para ser capaz de substituir a propriedade de todo, é claro. Outra opção é ter uma propriedade só de leitura na classe base que é definido a partir de um parâmetro de construtor:

abstract class Mother
{
    private readonly int myInt;
    public int MyInt { get { return myInt; } }

    protected Mother(int myInt)
    {
        this.myInt = myInt;
    }
}

class Daughter : Mother
{
    public Daughter() : base(1)
    {
    }
}

Isso é provavelmente a abordagem mais adequada se o valor não muda ao longo da vida da instância.

opção 2 é uma idéia ruim. Ele vai resultar em algo chamado de sombreamento; Basicamente, você tem dois membros diferentes "Myint", uma na mãe, e outro na filha. O problema com isso, é que os métodos que são implementados na mãe será referência "MyInt" da mãe enquanto métodos implementados na filha fará referência "MyInt" da filha. isso pode causar alguns problemas de legibilidade graves e confusão mais tarde para baixo da linha.

Pessoalmente, acho que a melhor opção é 3; porque fornece um valor centralizado clara, e pode ser referenciado internamente por crianças sem a necessidade de definir seus próprios campos -. que é o problema com a opção 1

Você pode definir algo como isto:

abstract class Father
{
    //Do you need it public?
    protected readonly int MyInt;
}

class Son : Father
{
    public Son()
    {
        MyInt = 1;
    }
}

Ao definir o valor como somente leitura, ele garante que o valor para essa classe permanece inalterada durante a vida útil do objeto.

Eu suponho que a próxima pergunta é: por que você precisa it

Você pode fazer isso

class x
{
    private int _myInt;
    public virtual int myInt { get { return _myInt; } set { _myInt = value; } }
}

class y : x
{
    private int _myYInt;
    public override int myInt { get { return _myYInt; } set { _myYInt = value; } }
}

Virtual permite que você obtenha uma propriedade de um corpo que faz algo e ainda permite que subclasses substituí-lo.

Se você está construindo uma classe e você quer que haja um valor base para a propriedade, em seguida, usar a palavra-chave virtual na classe base. Isto permite substituir opcionalmente o imóvel.

Usando o exemplo acima:

//you may want to also use interfaces.
interface IFather
{
    int MyInt { get; set; }
}


public class Father : IFather
{
    //defaulting the value of this property to 1
    private int myInt = 1;

    public virtual int MyInt
    {
        get { return myInt; }
        set { myInt = value; }
    }
}

public class Son : Father
{
    public override int MyInt
    {
        get {

            //demonstrating that you can access base.properties
            //this will return 1 from the base class
            int baseInt = base.MyInt;

            //add 1 and return new value
            return baseInt + 1;
        }
        set
        {
            //sets the value of the property
            base.MyInt = value;
        }
    }
}

Em um programa:

Son son = new Son();
//son.MyInt will equal 2

Eu iria com a opção 3, mas tem um método setMyInt abstrato que subclasses são forçados a implementar. Desta forma, você não terá o problema de uma classe derivada esquecendo-se de configurá-lo no construtor.

abstract class Base 
{
 protected int myInt;
 protected abstract void setMyInt();
}

class Derived : Base 
{
 override protected void setMyInt()
 {
   myInt = 3;
 }
}

A propósito, com uma opção, se você não especificar definir; em sua propriedade abstrata classe base, a classe derivada não terá de implementá-lo.

abstract class Father
{
    abstract public int MyInt { get; }
}

class Son : Father
{
    public override int MyInt
    {
        get { return 1; }
    }
}

Você pode ir com a opção 3 se você modificar sua classe base abstrata para exigir que o valor da propriedade no construtor, você não vai perder todos os caminhos. Eu realmente considerar esta opção.

abstract class Aunt
{
    protected int MyInt;
    protected Aunt(int myInt)
    {
        MyInt = myInt;
    }

}

É claro, então você ainda tem a opção de fazer o campo privado e, em seguida, dependendo da necessidade, expondo um getter propriedade pública protegida ou.

Eu fiz isso ...

namespace Core.Text.Menus
{
    public abstract class AbstractBaseClass
    {
        public string SELECT_MODEL;
        public string BROWSE_RECORDS;
        public string SETUP;
    }
}

namespace Core.Text.Menus
{
    public class English : AbstractBaseClass
    {
        public English()
        {
            base.SELECT_MODEL = "Select Model";
            base.BROWSE_RECORDS = "Browse Measurements";
            base.SETUP = "Setup Instrument";
        }
    }
}

Desta forma, você ainda pode usar campos.

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