추상 기본 클래스가 있으며이 부모 클래스에서 상속되는 각 클래스마다 다른 값을 갖는 필드 또는 속성을 선언하고 싶습니다.
기본 클래스 메소드에서이를 참조 할 수 있도록 기본 클래스 메소드에서이를 정의하려고합니다. 예를 들어 “이 오브젝트는 특성 / 필드 유형”이라는 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; }
}
}