get 무시하지만 설정되지 않음


78

를 정의하는 추상 클래스가 get있지만.이 아닌 set추상 클래스에 관한 한 get.

public abstract BaseClass
{
  public abstract double MyPop
  {get;}
}

그러나 일부 파생 클래스에서는 set속성이 필요하므로이 구현을 살펴보고 있습니다.

public class DClass: BaseClass
{
  public override double MyPop
  {get;set;}
}

문제는 컴파일 오류가 발생하여

* .set : *. 재정의 할 수있는 set 접근자가 없습니다.

위의 구문이 완벽하게 합법적이라고 생각하지만.

이것에 대한 아이디어가 있습니까? 해결 방법 또는 그 이유는 무엇입니까?

편집 : 내가 생각할 수있는 유일한 접근 방식 은 추상 클래스에서 get와 set같이 둘 다 넣고 하위 클래스가 NotImplementedExceptionif set가 호출되고 필요하지 않게하는 것입니다. 그것은 특별한 setter 메서드 와 함께 내가 좋아하지 않는 것 입니다.


이것을 조금 분해합시다. double각 클래스에서 특별히 구현 될 값 을 읽기 위해 메서드를 노출하는 클래스 집합을 빌드해야합니다 . 때로는이 값을 설정해야하므로 이러한 클래스 중 일부는이를 설정하는 방법을 노출해야합니다. 이게 옳은 거니? 얼마나 많은 상속 수준을 사용해야합니까?
— Codesleuth 2010 년

1
@Codesleuth : 네. 얼마나 많은 상속 수준에 대해 이것이 질문과 어떤 관련이 있는지 잘 모르겠습니다.
— Graviton

@David, 아이러니하게도 이것은 대답을 받아들이고 싶지 않은 질문처럼 보입니다.
— Graviton

3
나는 이것이 인터페이스에 대해 가능하지만 추상 클래스가 아닌 이유를 이해하지 못합니다. 무엇을 제공합니까?
— BlueRaja-Danny Pflughoeft

이거 너무 짜증나. 이것이 왜 불가능한지 이해하는 사람이 있습니까? get 및 set 속성은 실제로 컴파일 과정의 어딘가에있는 메서드에 상응하는 것으로 변환되지 않습니까? 그렇다면 이러한 방법의 가상 성은 고립 된 문제 일 수 있습니까? 편집 : 나는 어쩌면 내가 여기에 내 대답을 찾은 것 같아 : stackoverflow.com/questions/82437/...
— 마티아스 Nordqvist

답변:


15

C # 6.0의 새로운 기능 :

생성자 내에서 setter 만 호출하는 경우 읽기 전용 속성을 사용하여이 문제를 해결할 수 있습니다.

void Main()
{
    BaseClass demo = new DClass(3.6);
}

public abstract class BaseClass
{
    public abstract double MyPop{ get; }
}

public class DClass : BaseClass
{
    public override double MyPop { get; }
    public DClass(double myPop) { MyPop = myPop;}
}

4
이것은 사실이지만 문제에 대한 좋은 범용 솔루션은 아닙니다. 분명히 공개 세터가 필요한 경우가 많이있을 것입니다.
— Tom Bogle 2018 년

26

한 가지 가능한 대답은 getter를 재정의 한 다음 별도의 setter 메서드를 구현하는 것입니다. 속성 setter가 기본에 정의되지 않도록하려면 다른 옵션이 많지 않습니다.

public override double MyPop
{
    get { return _myPop; }
}

public void SetMyPop(double value)
{
    _myPop = value;
}

17

당신이 원하는 것을 할 수 없습니다. 추상 속성에서 setter를 정의해야합니다. 그렇지 않으면 올바르게 재정의 할 수 없습니다.

getter가 정의되고 getter / setter가 구현되는 위치를 아는 유일한 경우는 인터페이스를 사용하는 것입니다.

public interface IBaseInterface
{
    double MyPop { get; }
}

public class DClass : IBaseInterface
{
    public double MyPop { get; set; }
}

12
나쁜 접근법은 아닙니다. 그러나 때로는 인터페이스가 아닌 추상 클래스를 사용해야합니다.
— Graviton

@Graviton : C #에서 Default Interface Methods를 도입하면이 솔루션이 더 실용적이 될 것 입니다.
— Brian

8

경우 BaseClass자신의 코드베이스에, 당신은 할 수 있습니다 :

abstract public class BaseClass
{
    abstract public double MyPop { get; protected set; }
}

public class DClass : BaseClass
{
    private double _myProp;
    public override double MyProp
    {
        get { return _myProp; }
        protected set { _myProp = value; }
    }
}

편집 : 그런 다음 DClass 등에서 공용 메서드를 만들 수 있습니다 SetMyProp(double myProp). 도메인 모델에 대한 클래스 디자인은 기본 클래스에서 직접 속성을 설정할 수없는 이유와 파생 클래스에서 설정할 수있는 이유에 대해 명확하게 설명해야합니다.


좋아요,하지만 설정할 필요가없는 하위 클래스는 MyPop어떻습니까?
— Graviton

아마도 그들은 DClass가 아닌 BaseClass에서만 파생 될 수 있습니까?
— herzmeister 2010 년

그것은 내 앱에 좋은 생각이 아니라고 생각합니다. 상속은 is a언어 제한을 우회하는 것이 아니라 관계를 위해 예약되어야합니다 . 여기에있는 응용 프로그램에서 다른보다 현실적인 목적으로 상속을 사용하는 것 외에도.
— Graviton

1
나는 실제로이 문제에 문제가 없었고 OO 정확성에 열광적입니다. ;-) ... (OO에는 한계가 있지만, 당신을 염두에 두십시오) ... 아마도 당신의 정확한 시나리오에 대해 말할 때 모델에 대한 제안.
— herzmeister 2010 년

1
저는 여러분이 모델링하고 싶은 것을보고 싶은 실제 사례에 대해 더 많이 생각하고있었습니다. 예를 들어 Animal, Giraffe 및 Lion 클래스 또는 CelestialBody, Meteor 및 Planet 클래스가 있습니다.
— herzmeister 2010 년

5

하려는 일을하는 것이 방법을 찾았다면 좋은 디자인이 될 것이라고 확신하십니까?

하위 클래스의 개체가 부모 클래스의 개체가 만들 수없는 상태 변경을 수행 할 수 있습니다. Liskov 대체 원칙을 위반하지 않습니까?


2

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

abstract class TestBase { public abstract int Int { get; } }

class TestDerivedHelper : TestBase
{
    private int _Int;
    public override int Int
    {
        get
        {
            return _Int;
        }
    }

    protected void SetInt(int value)
    {
        this._Int = value;
    }
}

class TestDerived : TestDerivedHelper
{
    public new int Int
    {
        get { return base.Int; }
        set { base.SetInt(value); }
    }
}

TestDerived를 사용하면 원하는 기능이 제공됩니다. 이 메서드에서 볼 수있는 유일한 단점은 TestDerivedHelper에서 모든 추상 메서드를 구현해야하지만 나중에 더 많은 제어를 제공한다는 것입니다.

도움이 되었기를 바랍니다. ;)


2

이것이 불가능한 이유는 매개 변수가 C #에 의해 존재하도록 "매그 킹"되는 방식 때문입니다. 매개 변수를 정의 할 때 C #은 암시 적 getter 및 setter가 조작 하는 개인 필드를 만듭니다 . 기본 클래스에 setter가 없으면 하위 클래스에 작성된 메서드에서이 변수를 변경할 수 없습니다 (개인 플래그가 하위 클래스도 액세스하지 못하도록 금지하므로). 일반적으로 발생하는 것은 대신 기본 클래스의 암시 적 setter를 사용하는 것입니다.

모든 하위 클래스가이를 수행 할 수없는 경우 기본 클래스에 세트를 넣는 것은 권장하지 않습니다. 이는 다형성 프로그래밍의 전체 원칙에 위배되기 때문입니다 (추상 클래스에 정의 된 모든 추상 메서드는 하위 클래스에 의해 구현되어야 함). 다른 답변에서 설명한 것처럼 특별한 setter 메서드를 만드는 것이 가장 좋은 방법 일 것입니다.


1

포위

abstract class TestBase
{
    public abstract int Int { get; }
}

class TestDerivedHelper : TestBase
{
    private int _Int;
    public override int Int
    {
        get
        {
            return _Int;
        }
    }

    protected void SetInt(int value)
    {
        this._Int = value;
    }
}

class TestDerived : TestDerivedHelper
{
    public new int Int
    {
        get { return base.Int; }
        set { base.SetInt(value); }
    }
}

TestDerived를 사용하면 원하는 기능이 제공됩니다. 이 메서드에서 볼 수있는 유일한 단점은 TestDerivedHelper에서 모든 추상 메서드를 구현해야하지만 나중에 더 많은 제어를 제공한다는 것입니다.

저는이 접근 방식을 사용하고 저에게 매우 잘 작동합니다. 또한 "TestDerivedHelper"클래스도 추상화 한 다음 모든 메서드를 "TestDerived"클래스에서 구현해야합니다.


1

이 스레드가 오래되었지만 누군가에게 도움이 될 경우를 대비하여 내 솔루션을 배치하고 있습니다. 그것은 내 자신이 아니지만 다른 SO 주제의 답변을 기반으로합니다.

public abstract BaseClass
{
  public double MyPoP { get { return GetMyPoP; } }

  protected abstract double GetMyPoP { get; }
}

public class DClass: BaseClass
{
  public new double MyPoP { get; set; }

  protected override double GetMyPop { get { return MyPoP; } }
}

이 솔루션은 접근자를 수정해야하는 각 속성에 대한 추가 코드 줄을 추가합니다. 그러나 외부 가시성에는 변화가 없으며 필요한 기능을 제공합니다.


0
public abstract class BaseClass
{
    public abstract double MyPop { get; }
}

public class DClass: BaseClass
{
    private double _myPop = 0;
    public override double MyPop 
    {
        get { return _myPop; }
    }

    // some other methods here that use the _myPop field
}

외부에서 속성을 설정해야하는 경우 DClasssetter를 기본 클래스에 넣는 것이 더 낫습니다.


-2

편집하다:

좋아,이 응답에 성급했을지 모르지만 지금은 좀 더 생각해 보았습니다.

추상 기본 클래스를 사용해야합니까? 필요하지 않은 경우 다음을 시도하십시오.

public interface ISomeRelevantName
{
    double MyPop { get; }
}

public class DClass : ISomeRelevantName
{
    public double MyPop { get; set; }
}

2
추상적 인 특성 불평 것인가 MyPop에서이 BaseClass파생 클래스에서 구현되지 않습니다.
— Joey

흠, 내 대답 부끄러워 나 :( 나는 상점 편집으로이 문제를 해결할 것을 시도하고있다.
— Codesleuth

-3

private setter가있는 기본 클래스에 속성이있는 것이 아니라 setter가 필요한 하위 클래스에 속성이 있으면이를 재정의하고 공개로 설정하십시오.


6
추상적 인 접근을 할 수없는 개인 일
— 라비

abstract속성의 get또는 set접근의 private아날로그이다 protected. 따라서 기본 클래스에서 원하는 :public abstract MyProp { get; protected set; }
— JoeBrockhaus

-3

기본 클래스에는 set 접근자가 정의되어 있지 않으므로 set 접근자를 재정의 할 수 없습니다.

할 수있는 일은 new키워드를 사용하여 기본 클래스 구현을 숨기는 것이지만 원하는 것이 아닐 수도 있습니다.


1
기본 클래스는 추상적이고 구현을 가지지 않습니다 때문에, new작동하지 않을 수 있습니다.
— Joey

명확히하기 위해 : 파생 클래스가 추상 속성을 구현하지 않기 때문에 작동하지 않습니다. 위의 설명은 약간 부정확했을 수 있습니다.
— Joey

내 의견도 오해의 소지가 있었기 때문에 ( "new"가 전혀 작동 할 수 있다고 제안) 제거했습니다. 그래도 업데이트 주셔서 감사합니다.
— Benjamin Podszun 2010 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.