문제

왜 C#다음 코드를 허용되지 않:

public abstract class BaseClass
{
    public abstract int Bar { get;}
}

public class ConcreteClass : BaseClass
{
    public override int Bar
    {
        get { return 0; }
        set {}
    }
}

CS0546'ConcreteClass.됩니다.set':무시할 수 없기 때문에'공공 무.바이 없는 재정의 가능한 설정 접근

도움이 되었습니까?

해결책

때문에의 작가는 공공 무이 명시적으로 선언하는 바가 될 수 있습니다.그것은 이해되지 않는 한 파생 이 계약과 그것을 읽기/쓰기가 가능합니다.

나는 Microsoft 하나입니다.
말하자 나는 새로운 프로그래머들을 말하는 코드에 대한 공공 무 상속할 수 없습니다.나는 뭔가를 쓰는 것서는 바에 쓸 수 없습니다(이후 공공 무 명시하는 얻을만 제공).지금 당신의 유도,나의 코드가 손상될 수도 있습니다.예:

public class BarProvider
{ BaseClass _source;
  Bar _currentBar;

  public void setSource(BaseClass b)
  {
    _source = b;
    _currentBar = b.Bar;
  }

  public Bar getBar()
  { return _currentBar;  }
}

기 때문 바 설정할 수 없습니다 따라 공공 무 인터페이스,BarProvider 서는 캐싱을 안전하는 것이기 때문 바을 수정할 수 없습니다.하지만 설정한 경우에 가능했던 유도,이 클래스가 될 수 있는 제공 부패하는 경우 값을 누군가가 수정 _source 체의 바 시설 외부에서.는 점'개방하고 피하기 위해 비열한 것이고 놀라운 사람들'

업데이트: 일리아 Ryzhenkov'묻지 않는 이유 인터페이스 플레이하여 동일한 규칙이세요?' 흠..이 muddier 입으로 나는 그것에 대해 생각합니다.
인터페이스 계약을 말한다'기대하는 구현을 읽기 속성 이름이됩니다.' 개인적으로 나는 훨씬 덜하는 가정의 경우는 것을 보았 인터페이스입니다.볼 때 얻을만 객실에는 인터페이스,나는 그것을 읽으로'어떤 구현이 바 특성'...에는 기본 클래스 클릭으로'바는 읽기 전용 시설'.의 기술적으로 당신을 파괴하지 않는 것은 계약..당신이 하고 있는 더 있습니다.그래서 당신은 오른쪽에..내가 가까이'말로 만들로 가능한 오해를'.

다른 팁

나는 생각한 주요 이유는 단순히는 구문에 너무 명시하고 이 작업을 위해 어떤 다른 방법이다.이 코드:

public override int MyProperty { get { ... } set { ... } }

매우 명시적인 모두의 getset 은 무시합니다.이 없 set 기본 클래스에서,그렇게 컴파일러 뿌려줍니다.당신 같은 이를 무시할 수 없음 방법의 정의하지 않는 기본 클래스에서,당신은 이를 무시할 수 없음 setter 다.

당신이 말할 수 있는 컴파일러가지 생각해야의 기도만 적용됩 재정의하는 방법을 재정의할 수 있습니다(i.egetter 이 경우)이지만,이것에 대해 하나의 C#디자인 원칙-는 컴파일러가야 하는 추측이 아니라 당신의 의도가 있기 때문에,추측은 잘못이 없는 것입니다.

내가 생각하는 다음과 같은 구문을 할 수 있게,하지만 에릭 프라하라,구현 심지어 작은 기능은 다음과 같이 여전히 중요한 금액의 노력이...

public int MyProperty
{
    override get { ... }
    set { ... }
}

또한,autoimplemented 속성

public int MyProperty { override get; set; }

나는 우연히 발견 매우 동일한 문제는 오늘 제 생각에는 매우 유효한 이유 원다.

첫 번째 나는 다음과 같이라고 주장하는 얻을만 제공하지 않는 반드시 번역으로 읽기 전용입니다.나는 그것을 해석하기를"이 인터페이스에서/abtract 이 값을 가져올 수 있습니다."그는 것을 의미하지 않는 일부를 구현하는 인터페이스/추상 클래스로 늘 필요한 사용자/프로그램은 이 값을 설정하는 명시적으로 합니다.추상 클래스의 목적의 일부를 구현하는 데 필요한 기능이 있습니다.나는 절대적으로 아무 이유는 상속받은 클래스 수 없 추가 setter 을 위반하지 않고 어떤 계약이 있습니다.

다음과 같은 간단한 예제는 내가 필요로 오늘입니다.날짜가 한결같이 끈기와 열정의 길을 걸 내 인터페이스들을 모색하게 되었다.추가하는 이유가 이 세터 및를 추가하지 않고,SetProp 방법 중 하나 특히 인터페이스의 구현을 사용 DataContract/DataMember 직렬화를 위한의 소품이었을 것입니다 만들어 불필요하게 복잡하는 경우가 다른 추가 제공의 목적을 위해 serialization.

interface ITest
{
    // Other stuff
    string Prop { get; }
}

// Implements other stuff
abstract class ATest : ITest
{
    abstract public string Prop { get; }
}

// This implementation of ITest needs the user to set the value of Prop
class BTest : ATest
{
    string foo = "BTest";
    public override string Prop
    {
        get { return foo; }
        set { foo = value; } // Not allowed. 'BTest.Prop.set': cannot override because 'ATest.Prop' does not have an overridable set accessor
    }
}

// This implementation of ITest generates the value for Prop itself
class CTest : ATest
{
    string foo = "CTest";
    public override string Prop
    {
        get { return foo; }
        // set; // Not needed
    }
}

내가 이것을 알고 그냥"제 2 센트"게시물에,그러나 나는 느낌을 가진 원래 포스터하고 합리화하는 것 이것은 좋은 일이 나에게 이상한 것 같다,특히 고려하는 것과 동일한 제한이 적용되지 않 경우 상속에서 직접 인터페이스입니다.

도에 대해 언급을 사용하여 새로운 대신 재정의 적용되지 않습 여기에,그것은 단순히 일하지 않고도 그랬다면 그것은 없을 당신에게 결과를 제공하고 싶었,즉 가상 getter 에 설명된 대로 인터페이스입니다.

그것은 가능

tl;박사- 무시할 수 있는 유일한 방법으로 세터는 원하는 경우.그것은 기본적으로 그냥:

  1. new 시설 모두 getset 를 사용하여 동일한 이름입니다.

  2. 는 경우에 당신은 아무것도하지 않는 다른 다음,이전 get 방법은 여전히 호출될 경우 파생된 클래스가 호출을 통해 그것의 기본 유형입니다.이를 수정하려면 추가 abstract 중간층을 사용하는 override 이전 get 는 방법을 강제로 그것을 반환하는 새로운 get 방법의 결과입니다.

이렇게 우리를 재정의 속성과 get/set 는 경우에도 그들이 부족한 중에서 자신의 기본화질입니다.

보너스로 변경할 수도 있습니다익 유형은 당신이 원하는 경우.

  • 는 경우에는 기본 정의 get-단,다음 사용할 수 있습니다 더 많은 파생익 유형입니다.

  • 는 경우에는 기본 정의 set-단,다음할 수 있습 우리는 더 적은 파생익 유형입니다.

  • 는 경우 기본화질 이미 get/set, 다음

    • 사용할 수 있습니다 더 많은 파생익 유형 는 경우 당신이 그것을 만들 set-만

    • 당신이 사용할 수 있는 더 적은 파생익 유형 는 경우 당신이 그것을 만들 get-니다.

모든 경우에,당신은 당신을 유지할 수 있는 이와 같이 원하는 경우.아래의 예를 사용하여 같은 수익 유형 단순합니다.

황:기존의 get은 숙박 시설입니다.

당신이 어떤 수업 구성할 수 없다는 수정할 수 있습니다.어쩌면 그것은 단지 하나의 클래스,또는 그것의 기존 상속 트리입니다.어떤 경우,당신을 추가하고 싶 set 방법입니다,하지만 할 수 없습니다.

public abstract class A                     // Pre-existing class; can't modify
{
    public abstract int X { get; }          // You want a setter, but can't add it.
}
public class B : A                          // Pre-existing class; can't modify
{
    public override int X { get { return 0; } }
}

문제:할 수 없 overrideget-만 get/set

overrideget/set 객실이지만,그것은 없다.

public class C : B
{
    private int _x;
    public override int X
    {
        get { return _x; }
        set { _x = value; }   //  Won't compile
    }
}

솔루션:사 abstract 중간층

당신이 할 수있는 동안 바로 overrideget/set 제공,당신은 당신 :

  1. new get/set 의 속성과 동일한 이름입니다.

  2. override 이전 get 방법으로 접근하는 새로운 get 방법하여 일관성을 보장합니다.

그래서 작성 abstract 중간층:

public abstract class C : B
{
    //  Seal off the old getter.  From now on, its only job
    //  is to alias the new getter in the base classes.
    public sealed override int X { get { return this.XGetter; }  }
    protected abstract int XGetter { get; }
}

그 후,당신이 쓰는 클래스지 않을 컴파일하다.그것은 컴파일 이 시간이 있기 때문에 당신이 실제로 override'ing get은 숙박 시설입니다.;대신,당신이 그것을 대체 사용 new 키워드입니다.

public class D : C
{
    private int _x;
    public new virtual int X { get { return this._x; } set { this._x = value; } }

    //  Ensure base classes (A,B,C) use the new get method.
    protected sealed override int XGetter { get { return this.X; } }
}

결과:모든 것을 작품!

분명히,이 작품으로 의도에 대한 D.

var test = new D();
Print(test.X);      // Prints "0", the default value of an int.

test.X = 7;
Print(test.X);      // Prints "7", as intended.

여전히 모든 것을 작품으로도 볼 때 D 중 하나로 그것의 기본 클래스에서,예를 들어, AB.그러나 이유는,그것은 작품 수 있습니다 약간 적은 분명합니다.

var test = new D() as B;
//test.X = 7;       // This won't compile, because test looks like a B,
                    // and B still doesn't provide a visible setter.

그러나,기본 클래스의 정의 get 은 아직도 궁극적으로 재정의하여 파생된 클래스의 정의 get, 다,그래서 그것은 아직 완전히 일치한다.

var test = new D();
Print(test.X);      // Prints "0", the default value of an int.

var baseTest = test as A;
Print(test.X);      // Prints "7", as intended.

토론

이 방법을 추가할 수 있습 set 방법 get-만 속성입니다.할 수도 있습니다 그것을 사용하는 물건을 다음과 같:

  1. 속성을 변경으로 get-만, set-만,또는 getset 제공,관계없이 그것이 무엇인에서는 기본 클래스입니다.

  2. 변환한 유형의 방법에서 파생됩니다.

주요 단점은 거의 더 코딩을 할 추가 abstract class 에서 상속 트리입니다.이 될 수 있는 비트가 생성자와 함께는 매개 변수를 사람들 때문이 있을 복사/붙여넣은 중간층이다.

는 것에 동의하지 않정 getter 에서 파생된 형식 안티-패턴이다.읽기만 지정하는의 부족을 구현하지 않는 계약의 순수 기능성(암시하는 상 답변).

내가 심는 Microsoft 이 제한 하기 때문에 동일한 오해로 승진했고,또는 아마도 때문에 단순화법;하지만,이제는 범위에 적용될 수 있습을 얻을 설정 또는 개별적으로,아마도 우리는 무시할 수 있습니다.

오해에 표시된 상표,대답을 하는 읽기 전용 속성이 더"순수한"보다는 읽기/쓰기 속습니다.단순히 많은 일반적인 읽기 속성에 프레임워크;값이 일정하지 않/순수 기능성;예를 들어,날짜/시간입니다.지금은 읽기만,하지만 아무것도 하지만 순수한 기능적인 값입니다.도'캐시'의 값을 읽기만산의 가정하고 동일한 값을 반환합 다음에는 위험하다.

어떤 경우에,나는 사용 다음 방법 중 하나 이러한 한계를 극복하기 위해;모두 완벽한 보다는 보다 적게,하지만 당신은 다리를 절에 이어 결핍:

   class BaseType
   {
      public virtual T LastRequest { get {...} }
   }

   class DerivedTypeStrategy1
   {
      /// get or set the value returned by the LastRequest property.
      public bool T LastRequestValue { get; set; }

      public override T LastRequest { get { return LastRequestValue; } }
   }

   class DerivedTypeStrategy2
   {
      /// set the value returned by the LastRequest property.
      public bool SetLastRequest( T value ) { this._x = value; }

      public override T LastRequest { get { return _x; } }

      private bool _x;
   }

아마도 주위에 이동하여 문제를 새로 만들어 속성:

public new int Bar 
{            
    get { return 0; }
    set {}        
}

int IBase.Bar { 
  get { return Bar; }
}

내가 이해할 수있는 모든 포인트,하지만 효과적으로,C#3.0 자동 속성을 얻기에서 쓸모 있는 경우입니다.

당신은 아무것도 할 수 없습니다:

public class ConcreteClass : BaseClass
{
    public override int Bar
    {
        get;
        private set;
    }
}

IMO,C#을 제한해서는 안 그런 시나리오.그것은 개발자의 책임을 그에 따라 사용할 수 있습니다.

문제는 어떤 이유에서 Microsoft 결정이 있어야 세 가지 형태의 속성:읽기,쓰기만,읽기-쓰기,단지 하나의 존재할 수 있는 지정된 서명에 주어진다.성될 수 있으로 재정의 동일하게 선언 속성입니다.하이 무엇을 원하는 것이 필요할 것이 두 개를 만들 속성과 동일한 이름 및 서명--중 하나는 읽기 전용이며,하나의 읽기/쓰기가 가능합니다.

개인적으로,내가 원하는 전체 개념의"속성"될 수 있는 폐지는 것을 제외하고,속성-틱 구문을 사용될 수 있습으로 구문 설탕을 부르는"얻는"그리고"설정"방법이 있습니다.이 뿐만 아니라 용이 추가 설정한 옵션이지만,또한 허용을 반환하는 다른 유형에서'설정'.는 동안 이러한 기능을 사용할 수 없는 정말 자주 수 있습하는 것이 유용할 때에는'get'방법을 반환 래퍼체 동안 설정''받아들일 수 있거나는 래퍼 또는 실제 데이터입니다.

여기에는 작업이 주를 달성하기 위해서는 이를 사용하여 반사:

var UpdatedGiftItem = // object value to update;

foreach (var proInfo in UpdatedGiftItem.GetType().GetProperties())
{
    var updatedValue = proInfo.GetValue(UpdatedGiftItem, null);
    var targetpropInfo = this.GiftItem.GetType().GetProperty(proInfo.Name);
    targetpropInfo.SetValue(this.GiftItem, updatedValue,null);
}

이 방법을 설정할 수 있습 객체 속성 값을 읽기 전용입니다.에서 작동하지 않을 수 있습은 모든 시나리오니다.

당신은 변경해야의 질문의 제목 또는 당신의 질문은 전적으로 관해서 재정의 추상적인 시설,또는 당신의 질문에서 관련하여 일반적으로 재정의 클래스의를 얻습니다.


이전 (재정의 추상적성)

는 코드입니다.기본 클래스가 혼자서 말하면 안 되는 당신이 당신을 강요하는 재정의를 얻은 숙박 시설입니다.(아마 인터페이스).기본 클래스 일반적인 기능이 요구될 수 있는 특정 입력에서 구현하는 클래스입니다.따라서,일반적인 기능을 할 수 있습 통화를 추상적인 속성이나 방법이 있습니다.에 주어진 경우,일반적인 방법 기능을 요청해야에 대한 재정의 추상적인 방법과 같은:

public int GetBar(){}

하지만 경우에 당신 통제 할 수 없는,그의 기능을 기본 클래스에서 읽고는 자신의 공용 시설(이상)다음 다음과 같이 하면 됩니다:

public abstract class BaseClass
{
    public abstract int Bar { get; }
}

public class ConcreteClass : BaseClass
{
    private int _bar;
    public override int Bar
    {
        get { return _bar; }
    }
    public void SetBar(int value)
    {
        _bar = value;
    }
}

고 싶은 포인트(이상)논평:내가 말할 것 최고의 관행은 클래스를 사용하지 않는 자신의 공공성,하지만 사용하는 개인/보호할 때 필드 그들이 존재합니다.그래서 이것은 더 나은 패턴:

public abstract class BaseClass {
    protected int _bar;
    public int Bar { get { return _bar; } }
    protected void DoBaseStuff()
    {
        SetBar();
        //Do something with _bar;
    }
    protected abstract void SetBar();
}

public class ConcreteClass : BaseClass {
    protected override void SetBar() { _bar = 5; }
}

후자의 경우 (재정의 클래스의를 얻은 숙박 시설입니다.)

모든 non-추상적인 숙박 시설에는 setter.그렇지 않으면 쓸모없다고 걱정하면 안된다.Microsoft 없을 할 수 있도록 당신이 무엇을 원합니다.이유:세터에 존재하는 어떤 형태 또는 다른 달성할 수 있 당신이 무엇을 원 Veerryy 쉽습니다.

기본 클래스고,또는 모든 클래스에는 읽을 수 있는 시설 {get;}, 가 종의 노출에 대한 세터는을 제공합니다.메타데이터는 다음과 같습니다.

public abstract class BaseClass
{
    public int Bar { get; }
}

하지만 구현해야 두 끝의 스펙트럼의 복잡성:

적어도 복잡:

public abstract class BaseClass
{
    private int _bar;
    public int Bar { 
        get{
            return _bar;
        }}
    public void SetBar(int value) { _bar = value; }
}

가장 복잡:

public abstract class BaseClass
{
    private int _foo;
    private int _baz;
    private int _wtf;
    private int _kthx;
    private int _lawl;

    public int Bar
    {
        get { return _foo * _baz + _kthx; }
    }
    public bool TryDoSomethingBaz(MyEnum whatever, int input)
    {
        switch (whatever)
        {
            case MyEnum.lol:
                _baz = _lawl + input;
                return true;
            case MyEnum.wtf:
                _baz = _wtf * input;
                break;
        }
        return false;
    }
    public void TryBlowThingsUp(DateTime when)
    {
        //Some Crazy Madeup Code
        _kthx = DaysSinceEaster(when);
    }
    public int DaysSinceEaster(DateTime when)
    {
        return 2; //<-- calculations
    }
}
public enum MyEnum
{
    lol,
    wtf,
}

내 포인트 인,어느 쪽이든,당신은 세터 노출됩니다.귀하의 경우에,당신은 당신할 수 있습을 재정의 int Bar 원하지 않기 때문에 기본 클래스를,그것을 처리에 액세스할 수 없는 방법을 검토 그것은 그것을 처리 또는 임무가 주어졌하다 일부는 실제 코드에 빠른'n'dirty 에 대하여 당신의 것입니다.

모두 후반과 이전 (끝)

긴 이야기를 짧은:그것은 필요하지 않습 Microsoft 하는 것입니다.당신이 선택할 수 있는 방법을 구현하는 클래스가 설정하고,산세 생성자,사용 또는 기본 클래스입니다.

솔루션을 위한 작은 하위 집합이 사용의 경우,그럼에도 불구하고:C#6.0"readonly"세터에 자동으로 추가를 위한 재정의 getter-만 속성입니다.

public abstract class BaseClass
{
    public abstract int Bar { get; }
}

public class ConcreteClass : BaseClass
{
    public override int Bar { get; }

    public ConcreteClass(int bar)
    {
        Bar = bar;
    }
}

기 때문에 IL 수준,읽기/쓰기 속으로 변환하는 두 가지(getter 및 setter)방법이 있습니다.

재정의하는 경우,당신은하지 않는 근본적인 인터페이스입니다.할 수 있다면 추가 세터,당신은 것이 효과적으로 추가 할 수 있는 새로운 방법,남아있는 보이지 않는 외부 세계로 당신의 클래스의 인터페이스가 우려하고있다.

True 를 추가하는 새로운 방법이 될 수 없 호환성을 파괴 per se,하지만 이 남아 있을 것 이 숨겨 결정을 허용하지 않는 이렇게 완벽한 의미가 있습니다.

기 때문에 휴식의 개념을 캡슐화 및 구현 숨어있다.경우를 고려할 때 당신은 클래스를 만들고,그것을 발송한 다음,소비자의 클래스에게 자신이 설정 할 수 있는 시설을 원래를 제공합 getter 니다.그것은 것이 효과적으로 방해 어떤 고정의할 수 있는 클래스에 따라 달라집에서 구현됩니다.

기 때문에 클래스는 읽기 전용 시설(no setter)아마 이유가 있을 수 있습니다.되지 않을 수도 있습니 어떤 기본적인 데이터 저장소에 대한 예입니다.을 만들 수 있도록 세터 휴식의 계약에 명시된 규정 클래스입니다.그것은 단지 나쁜 OOP.

읽기만 숙박 시설에는 기본 클래스는 것을 나타냅 이 숙박 시설 값을 나타내는 항상 있을 수 있 결정된 클래스에서(예를 들어 enum 값과 일치하는(db)컨텍스트의 객체).그래서 responsibillity 의 가치를 결정 내에서 클래스입니다.

추가 setter 원인이 어려운 문제가 여기:유효성 검사 오류가 발생한 경우 설정 값을 다른 것보다는 하나의 가능한 값은 이미 그렇게 되었습니다.

규칙은 종종 그러나 예외.그것은 매우 잘 가능성에 대한 예 중 하나에서 파생된 클래스의 컨텍스트를 좁혀 가능한 enum 값 아래로 3 10,아직 사용자의 이전을 결정하는 하나의 올바른 것입니다.파생된 클래스 요구에 위임하 responsibillity 의 가치를 결정하여 사용자의 이 객체입니다.중요한 것을 깨닫 는 사용자의 이체 잘 알고 있어야의 예외 가정 responsibillity 올바른 값을 설정.

나의 솔루션은 이러한 종류의 상황에 있는 것이를 떠날 수 있는 시설 읽기 전용이며 새로 추가 읽기/쓰기 속성을 파생된 클래스를 지원하는 예외는 아니다.의 재정의 원성은 단순히 반환 값의 새로운 제공합니다.새로운 제공할 수 있는 적당한 이름을 나타내는 컨텍스트의 이 예외니다.

이것은 또한 지원이 유효한 말:"그것으로 가능한 하드에 대한 오해하는 농작물"에 의해 Gishu.

이것은 불가능하지 않습니다.당신은 단순히 사용하"새로운"키워드에 당신을 제공합니다.예를 들어,

namespace {
    public class Base {
        private int _baseProperty = 0;

        public virtual int BaseProperty {
            get {
                return _baseProperty;
            }
        }

    }

    public class Test : Base {
        private int _testBaseProperty = 5;

        public new int BaseProperty {
            get {
                return _testBaseProperty;
            }
            set {
                _testBaseProperty = value;
            }
        }
    }
}

그것으로 나타나는 경우는 이 방법을 만족하는 이 양쪽의 토론입니다."를 사용하여 새로운"휴식 사이의 계약 기본 클래스를 구현 및위 클래스를 구현합니다.이 때 필요한 클래스를 가질 수 있습니다 여러 계약(중 하나를 통해 인터페이스 또는 기본 클래스).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top