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 접근자가 없습니다.

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

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

편집 : 내가 생각할 수있는 유일한 접근 방식 은 추상 클래스에서 getset같이 둘 다 넣고 하위 클래스가 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.