[C#] 서브 클래스에서 필드 또는 속성 재정의

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

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

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

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

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

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

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의 문제입니다.


답변

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

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


답변

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

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

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

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

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


답변

클래스를 작성 중이고 특성의 기본 값이 필요한 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; }
    }
}