Alt sınıflardaki alanları veya özellikleri geçersiz kılma


145

Soyut bir temel sınıf var ve bir alan veya bu üst sınıftan devralan her sınıfta farklı bir değere sahip bir özellik bildirmek istiyorum.

Temel sınıf yönteminde başvurabilirsiniz böylece baseclass içinde tanımlamak istiyorum - örneğin "Bu nesne türü özellik / alan olduğunu" demek için ToString geçersiz kılma . Bunu yaparken görebildiğim üç yol var, ama merak ediyordum - bunu yapmanın en iyi ya da kabul edilen yolu nedir? Acemi soru, üzgünüm.

Seçenek 1:
Soyut bir Özellik kullanın ve devralınan sınıflarda geçersiz kılın. Bu zorlanmaktan yararlanır (geçersiz kılmanız gerekir) ve temizdir. Ancak, bir alanı kapsüllemek yerine sabit kod değerini döndürmek biraz yanlış hissettirir ve sadece kod satırları yerine birkaç satırdır. Ayrıca "set" için bir vücut beyan etmek zorundayım ama bu daha az önemli (ve muhtemelen farkında olmadığım bir şeyden kaçınmanın bir yolu var).

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

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

Seçenek 2
Ortak bir alan (veya korunan bir alan) bildirebilir ve miras alınan sınıfta açıkça geçersiz kılabilirim. Aşağıdaki örnek bana "yeni" kullanmak için bir uyarı verecektir ve muhtemelen bunu yapabilirim, ancak yanlış geliyor ve bütün mesele olan polimorfizmi bozuyor. İyi bir fikir gibi görünmüyor ...

abstract class Mother
{
    public int MyInt = 0;
}

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

Seçenek 3
Korumalı bir alan kullanabilir ve değeri yapıcıda ayarlayabilirim. Bu oldukça düzenli görünüyor ama bana her zaman kurucu bunu ayarlar ve aşırı yüklü kurucuları ile her zaman bazı kod yolu değeri ayarlama şansı vardır güveniyor.

abstract class Aunt
{
    protected int MyInt;
}

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

Bu biraz teorik bir soru ve sanırım tek seçenek güvenli olduğu için cevap seçenek 1 olmalı ama sadece C # ile başa çıkıyorum ve daha fazla deneyime sahip insanlara sormak istedim.


soyut kamu int MyInt {get; set;} => genel soyut dize IntentName {get; set;}: D
Navid Golforoushan

Yanıtlar:


136

Üç çözümlerin sadece Seçenek 1 olduğunu polimorfik .

Alanların kendileri geçersiz kılınamaz. Bu nedenle Seçenek 2 yeni anahtar kelime uyarısını döndürür .

Uyarının çözümü “yeni” anahtar kelimeyi eklemek değil, Seçenek 1'i uygulamaktır.

Alanınızın polimorfik olması gerekiyorsa, onu bir Mülke sarmanız gerekir.

Seçenek 3Polimorfik davranışa ihtiyacınız yoksa tamamdır. Bununla birlikte, çalışma zamanında MyInt özelliğine erişildiğinde, türetilen sınıfın döndürülen değer üzerinde herhangi bir kontrolü olmadığını hatırlamanız gerekir. Temel sınıf kendi başına bu değeri döndürebilir.

Mülkünüzün gerçekten polimorfik bir uygulaması bu şekilde görünebilir ve türetilmiş sınıfların kontrol altında olmasına izin verir .

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 */ }
    }
}

154
Bir yana, Baba'nın "Y" formülünü ve Anne'yi mantıksal olarak "X" formülünü uygulaması gerektiğini düşünüyorum .
Peter - Monica'yı eski

4
Ebeveyn'de varsayılan bir uygulama sağlamak ve soyut olmamasını istersem ne olur?
Aaron Franke

@AaronFranke İmzayı oluşturun: public virtual int MyInt {get; }
Ted Bigham

@ Peter-
ReinstateMonica

18

Seçenek 2, başlangıç ​​olmayan bir öğedir - alanları geçersiz kılamazsınız, yalnızca gizleyebilirsiniz .

Şahsen, her seferinde 1. seçeneğe giderdim. Alanları her zaman gizli tutmaya çalışıyorum. Tabii ki, bu özelliği gerçekten geçersiz kılabilmeniz gerekiyorsa. Diğer bir seçenek, base sınıfında bir yapıcı parametresinden ayarlanan salt okunur bir özelliğe sahip olmaktır:

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)
    {
    }
}

Değer, örneğin ömrü boyunca değişmezse, muhtemelen en uygun yaklaşım budur.


Bunu şu an için doğru olmadığını söyleyebilir miyiz msdn.microsoft.com/tr-tr/library/9fkccyh4.aspx msdn makalesinde özellikleri geçersiz kılabileceğiniz gösterilmektedir
kodlama

1
@codingbiz: cevabım özellikler hakkında nerede konuşuyor? Alanlar ve özellikler aynı şey değildir.
Jon Skeet

@codingbiz: (Cevabım şu anda mülklerden bahsediyor, kuşkusuz - ama onları geçersiz kılamayacağınızı asla söylemedi. Dedi - ve hala doğru olan alanları geçersiz kılamayacağınızı söyledi .)
Jon Skeet

7

seçenek 2 kötü bir fikirdir. Gölgeleme denilen bir şeyle sonuçlanacaktır; Temelde, biri annede diğeri kızda olmak üzere iki farklı "MyInt" üyeniz var. Buradaki sorun, annede uygulanan yöntemlerin annenin "MyInt" 'ine bakarken, kızda uygulanan yöntemler ise kızın "MyInt"' sine başvurmasıdır. bu, bazı ciddi okunabilirlik sorunlarına ve daha sonra karışıklığa neden olabilir.

Şahsen, en iyi seçenek 3 olduğunu düşünüyorum; çünkü net bir merkezi değer sağlar ve kendi alanlarını tanımlama zahmetine girmeden çocuklar tarafından dahili olarak referanslandırılabilir - bu seçenek 1'deki problemdir.


6

Bunu yapabilirsin

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, bir özelliği bir şeyler yapan bir gövde almanıza ve yine de alt sınıfların onu geçersiz kılmasına izin verir.


4

Bunun gibi bir şey tanımlayabilirsiniz:

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

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

Değeri salt okunur olarak ayarlayarak, söz konusu sınıfın değerinin nesnenin ömrü boyunca değişmeden kalmasını sağlar.

Sanırım bir sonraki soru: neden buna ihtiyacınız var?


Statik kelimelerin kötü bir seçimidir, çünkü değerin daha sonra sınıfın tüm örnekleri arasında paylaşıldığını ima eder, ki elbette öyle değildir.
Winston Smith

3

Bir sınıf oluşturuyorsanız ve özellik için bir temel değer olmasını istiyorsanız virtual, temel sınıftaki anahtar sözcüğü kullanın . Bu, isteğe bağlı olarak özelliği geçersiz kılmanıza olanak tanır.

Yukarıdaki örneğinizi kullanarak:

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

Bir programda:

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

0

Seçenek 3 ile gitmek istiyorum, ama alt sınıfları uygulamak zorunda soyut bir setMyInt yöntemi var. Bu şekilde, türetilmiş bir sınıfın yapıcıda ayarlamayı unutması sorunu yaşamayacaksınız.

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

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

Bu arada, bir seçenekle, set belirtmezseniz; soyut temel sınıf özelliğinizde, türetilmiş sınıf bunu uygulamak zorunda kalmaz.

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

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

0

Soyut temel sınıfınızı yapıcıda özellik değeri gerektirecek şekilde değiştirirseniz, seçenek 3 ile gidebilirsiniz, hiçbir yolu kaçırmazsınız. Bu seçeneği gerçekten düşünürdüm.

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

}

Tabii ki, o zaman hala alanı özel yapma seçeneğine sahipsiniz ve ihtiyaca göre korumalı veya kamu mülkiyetine sahip bir kişiyi ortaya çıkarabilirsiniz.


0

Bunu ben yaptım...

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

Bu şekilde alanları kullanmaya devam edebilirsiniz.


Bunun prototip veya demo için geçici bir çözüm olarak iyi olduğunu hissediyorum.
Zimano

0

Uygulama ile soyut bir sınıf olmasını istediğinizde örnek uygulama. Alt sınıflar:

  1. Soyut bir sınıfın uygulanmasını parametrelendirin.
  2. Soyut sınıfın uygulanmasını tamamen miras;
  3. Kendi uygulamanız var.

Bu durumda, uygulama için gerekli olan özellikler soyut sınıf ve kendi alt sınıfı dışında kullanılamaz.

    internal abstract class AbstractClass
    {
        //Properties for parameterization from concrete class
        protected abstract string Param1 { get; }
        protected abstract string Param2 { get; }

        //Internal fields need for manage state of object
        private string var1;
        private string var2;

        internal AbstractClass(string _var1, string _var2)
        {
            this.var1 = _var1;
            this.var2 = _var2;
        }

        internal void CalcResult()
        {
            //The result calculation uses Param1, Param2, var1, var2;
        }
    }

    internal class ConcreteClassFirst : AbstractClass
    {
        private string param1;
        private string param2;
        protected override string Param1 { get { return param1; } }
        protected override string Param2 { get { return param2; } }

        public ConcreteClassFirst(string _var1, string _var2) : base(_var1, _var2) { }

        internal void CalcParams()
        {
            //The calculation param1 and param2
        }
    }

    internal class ConcreteClassSecond : AbstractClass
    {
        private string param1;
        private string param2;

        protected override string Param1 { get { return param1; } }

        protected override string Param2 { get { return param2; } }

        public ConcreteClassSecond(string _var1, string _var2) : base(_var1, _var2) { }

        internal void CalcParams()
        {
            //The calculation param1 and param2
        }
    }

    static void Main(string[] args)
    {
        string var1_1 = "val1_1";
        string var1_2 = "val1_2";

        ConcreteClassFirst concreteClassFirst = new ConcreteClassFirst(var1_1, var1_2);
        concreteClassFirst.CalcParams();
        concreteClassFirst.CalcResult();

        string var2_1 = "val2_1";
        string var2_2 = "val2_2";

        ConcreteClassSecond concreteClassSecond = new ConcreteClassSecond(var2_1, var2_2);
        concreteClassSecond.CalcParams();
        concreteClassSecond.CalcResult();

        //Param1 and Param2 are not visible in main method
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.