development

서브 클래스에서 필드 또는 속성 재정의

big-blog 2020. 6. 26. 07:44
반응형

서브 클래스에서 필드 또는 속성 재정의


추상 기본 클래스가 있으며이 부모 클래스에서 상속되는 각 클래스마다 다른 값을 갖는 필드 또는 속성을 선언하고 싶습니다.

기본 클래스 메소드에서이를 참조 할 수 있도록 기본 클래스 메소드에서이를 정의하려고합니다. 예를 들어 "이 오브젝트는 특성 / 필드 유형"이라는 ToString을 대체합니다 . 나는 이것을 할 수있는 세 가지 방법을 가지고 있지만 궁금합니다.이 일을하는 가장 좋은 방법은 무엇입니까? 초보자 질문입니다. 죄송합니다.

옵션 1 :
추상 속성을 사용하여 상속 된 클래스에서 재정의하십시오. 이 기능을 적용하면 (재정의해야 함) 이점이 있으며 깨끗합니다. 그러나 필드를 캡슐화하는 대신 하드 코드 값을 반환하는 것은 약간 잘못 느끼고 단지 코드가 아닌 몇 줄의 코드입니다. 또한 "세트"에 대해 본문을 선언해야하지만 덜 중요합니다 (아마도 내가 모르는 것을 피할 수있는 방법이 있습니다).

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

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

옵션 2
공용 필드 (또는 보호 된 필드)를 선언하고 상속 된 클래스에서 명시 적으로 재정의 할 수 있습니다. 아래 예제는 "새"를 사용하라는 경고를 주며 아마도 그렇게 할 수 있지만 잘못 느꼈고 다형성을 깨뜨 렸습니다. 좋은 생각이 아닌 것 같습니다 ...

abstract class Mother
{
    public int MyInt = 0;
}

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

옵션 3
보호 된 필드를 사용하고 생성자에서 값을 설정할 수 있습니다. 이것은 꽤 깔끔한 것처럼 보이지만 생성자가 항상 이것을 설정하고 여러 개의 오버로드 된 생성자가 있으면 일부 코드 경로가 값을 설정하지 않을 가능성이 있습니다.

abstract class Aunt
{
    protected int MyInt;
}

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

그것은 약간의 이론적 인 질문이며 대답은 유일한 안전한 옵션 이므로 옵션 1이어야한다고 생각합니다. 하지만 C #에 익숙해지고 더 많은 경험을 가진 사람들에게 물어보고 싶었습니다.


세 가지 솔루션의 옵션 1다형성 .

필드 자체는 무시할 수 없습니다. 이것이 바로 옵션 2새로운 키워드 경고를 반환하는 이유 입니다.

경고에 대한 해결책은“new”키워드를 추가하는 것이 아니라 옵션 1을 구현하는 것입니다.

필드가 다형성이어야하는 경우 속성으로 래핑해야합니다.

다형성 동작이 필요없는 경우 옵션 3 은 정상입니다. 그러나 런타임에 MyInt 특성에 액세스 할 때 파생 클래스는 리턴 된 값에 대한 제어가 없음을 기억해야합니다. 기본 클래스 자체는이 값을 반환 할 수 있습니다.

이것은 당신의 속성의 진정한 다형성 구현이 어떻게 보일지에 따라 파생 클래스가 제어되도록 합니다.

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

옵션 2는 스타터가 아니며 필드를 무시할 수 없으며 숨길 수만 있습니다.

개인적으로 매번 옵션 1을 선택했습니다. 필드를 항상 비공개로 유지하려고합니다. 물론 실제로 속성을 무시할 수 있어야하는 경우입니다. 또 다른 옵션은 생성자 매개 변수에서 설정 한 기본 클래스에 읽기 전용 특성을 갖는 것입니다.

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

인스턴스 수명 기간 동안 값이 변경되지 않는 경우 가장 적합한 방법 일 것입니다.


옵션 2는 나쁜 생각입니다. 섀도 잉이라는 결과가 나옵니다. 기본적으로 두 개의 다른 "MyInt"멤버가 있습니다. 하나는 어머니와 다른 하나는 딸입니다. 이에 대한 문제는 어머니에서 구현 된 메소드가 어머니의 "MyInt"를 참조하고 딸에서 구현 된 메소드는 딸의 "MyInt"를 참조한다는 것입니다. 이로 인해 심각한 가독성 문제가 발생하고 나중에 혼란 스러울 수 있습니다.

개인적으로 최선의 선택은 3이라고 생각합니다. 명확한 중앙 집중식 값을 제공하고 자체 필드를 정의하는 번거 로움없이 내부적으로 참조 할 수 있기 때문에 옵션 1의 문제입니다.


다음과 같이 정의 할 수 있습니다.

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

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

값을 읽기 전용으로 설정하면 해당 클래스의 값이 객체 수명 동안 변경되지 않은 상태로 유지됩니다.

다음 질문은 왜 필요합니까?


당신은 이것을 할 수 있습니다

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을 사용하면 무언가를 수행하는 바디를 프로퍼티로 가져올 수 있으며 여전히 서브 클래스가이를 오버라이드 할 수 있습니다.


클래스를 작성 중이고 특성의 기본 값이 필요한 virtual경우 기본 클래스에서 키워드 를 사용하십시오 . 이를 통해 선택적으로 속성을 재정의 할 수 있습니다.

위의 예를 사용하여 :

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

프로그램에서 :

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

옵션 3을 사용 하겠지만 하위 클래스를 강제로 구현하는 추상 setMyInt 메소드가 있습니다. 이렇게하면 생성자에서 클래스를 설정하는 것을 잊어 버린 파생 클래스의 문제가 발생하지 않습니다.

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

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

그건 그렇고, 옵션 1을 사용하여 set을 지정하지 않으면; 추상 기본 클래스 속성에서 파생 클래스는이를 구현할 필요가 없습니다.

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

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

생성자에서 속성 값을 요구하도록 추상 기본 클래스를 수정하면 옵션 3을 사용할 수 있습니다. 경로를 놓치지 마십시오. 나는이 옵션을 정말로 고려할 것입니다.

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

}

물론 필드를 비공개로 설정하고 필요에 따라 보호 또는 공공 재산 게터를 노출시킬 수 있습니다.


나는 이걸했다...

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

이 방법으로 필드를 계속 사용할 수 있습니다.


구현을 가진 추상 클래스를 원할 때 구현 예제. 서브 클래스는 반드시 :

  1. 추상 클래스의 구현을 매개 변수화하십시오.
  2. 추상 클래스의 구현을 완전히 상속합니다.
  3. 직접 구현하십시오.

In this case, the properties that are necessary for the implementation should not be available for use except for the abstract class and its own subclass.

    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
    }

참고URL : https://stackoverflow.com/questions/326223/overriding-fields-or-properties-in-subclasses

반응형