2011-01-10 4 views
37

Ich versuche, eine abstrakte Klasse zu erstellen, die eine Eigenschaft mit einem Getter definiert. Ich möchte es abgeleiteten Klassen überlassen, um zu entscheiden, ob sie einen Setter für die Eigenschaft implementieren wollen oder nicht. Ist das möglich?Abstrakte Eigenschaft mit öffentlichen Getter, definieren private Setter in konkrete Klasse möglich?

Was ich habe, so weit:

public abstract class AbstractClass { 
    public abstract string Value { get; } 
    public void DoSomething() { 
     Console.WriteLine(Value); 
    } 
} 

public class ConcreteClass1 : AbstractClass { 
    public override string Value { get; set; } 
} 

public class ConcreteClass2 : AbstractClass { 
    private string _value; 
    public override string Value { 
     get { return _value; } 
    } 
    public string Value { 
     set { _value = value; } 
    } 
} 

public class ConcreteClass3 : AbstractClass { 
    private string _value; 
    public override string Value { 
     get { return _value; } 
    } 
    public void set_Value(string value) { 
     _value = value; 
    } 
} 

In ConcreteClass1, erhalte ich einen Fehler auf dem set. Es kann set_Value nicht außer Kraft setzen, da in AbstractClass kein Overridable-Set-Accessor existiert.

In ConcreteClass2, bekomme ich einen Fehler auf beiden Value 's, weil ein Mitglied mit dem gleichen Namen bereits deklariert ist.

ConcreteClass3 gibt keinen Fehler, aber obwohl Value Set-Accessor in Set_Value kompiliert werden würde, funktioniert es andersherum nicht. Das Definieren einer set_Value bedeutet nicht, dass Value einen Set-Accessor erhält. Daher kann ich einer ConcreteClass3.Value-Eigenschaft keinen Wert zuweisen. I kann verwenden ConcreteClass3.set_Value ("Wert"), aber das ist nicht das, was ich hier erreichen möchte.

Ist es möglich, dass die abstrakte Klasse einen öffentlichen Getter fordert, während ein optionaler Setter in einer abgeleiteten Klasse definiert werden kann?

Falls Sie sich fragen, das ist nur eine theoretische Frage. Ich habe keine reale Situation, in der so etwas benötigt wird. Aber ich kann mir eine abstrakte Klasse vorstellen, der es egal ist, wie eine Eigenschaft gesetzt wird, aber das muss die Eigenschaft bekommen können.

Antwort

28

Leider können Sie nicht genau das tun, was Sie wollen. Sie können dies jedoch mit Schnittstellen tun:

public interface IInterface { 
    string MyProperty { get; } 
} 

public class Class : IInterface { 
    public string MyProperty { get; set; } 
} 

So wie ich tun würde, es eine separate SetProperty-Methode in den konkreten Klassen zu haben ist:

public abstract class AbstractClass { 
    public abstract string Value { get; } 
} 

public class ConcreteClass : AbstractClass { 

    private string m_Value; 
    public override string Value { 
     get { return m_Value; } 
    } 

    public void SetValue(string value) { 
     m_Value = value; 
    } 
} 
+0

Mit der 'Schnittstelle' kann ich die' DoSomething' Methode in meiner Basisklasse nicht implementieren (es gibt keine Basisklasse, nur eine Schnittstelle). 'SetValue' ist das selbe wie' set_Value' in meiner 'ConcreteClass3'. Aber wenn das der richtige Weg ist, ist es wahrscheinlich besser, 'SetValue' zu ​​benennen als' set_Value'. – comecme

+0

Der Grund set_Value ist nicht mit der Eigenschaft verknüpft, da in der Assembly eine explizite Definition 'PropertyDef' vorhanden ist, die die Methoden' get_' und 'set_' verknüpft; Die einfache Benennung einer Methode 'set_' verbindet sie nicht mit einer Eigenschaft. Es gibt keine Möglichkeit, genau das zu tun, was Sie in C# wollen; Sie werden Kompromisse eingehen müssen. – thecoop

+0

Sie können 'DoSomething' als eine Erweiterungsmethode für' IInterface' implementieren. Siehe meine Bearbeitung. – piedar

0

Nicht sehr elegant, aber es ist in der Nähe können Sie bekommen, ohne etwas zu tun, wie Sie in concreteclass3

public class Concrete : AbstractClass 
{ 
    public new void DoSomething() 
    { 
     Console.WriteLine(Value); 
    } 
} 

public abstract class AbstractClass 
{ 
    protected AbstractClass() 
    { 
     try 
     { 
      var value = Value; 
     } 
     catch (NotImplementedException) 
     { 
      throw new Exception("Value's getter must be overriden in base class"); 
     } 
    } 
    public void DoSomething() 
    { 
     Console.WriteLine(Value); 
    } 

    /// <summary> 
    /// Must be override in subclass 
    /// </summary> 
    public string Value { get { throw new NotImplementedException(); } } 
} 
+0

Ich sehe nicht, warum Sie ein 'neues DoSomething' in der konkreten Klasse definieren. Außerdem löst Ihre Lösung zur Laufzeit eine Ausnahme aus, während der Kompilierzeit wird das Fehlen einer Value-Implementierung überhaupt nicht bemerkt. – comecme

5

eine Lösung gefunden haben: How to override a getter-only property with a setter in C#?

public abstract class A 
{ 
    public abstract int X { get; } 
} 
public class B : A 
{ 
    public override int X { get { return 0; } } 
} 
/*public class C : B //won't compile: can't override with setter 
{ 
    private int _x; 
    public override int X { get { return _x; } set { _x = value; } } 
}*/ 
public abstract class C : B //abstract intermediate layer 
{ 
    public sealed override int X { get { return this.XGetter; } } 
    protected abstract int XGetter { get; } 
} 
public class D : C //does same thing, but will compile 
{ 
    private int _x; 
    protected sealed override int XGetter { get { return this.X; } } 
    public new virtual int X { get { return this._x; } set { this._x = value; } } 
} 

ist nun äquivalent zu einer Klasse, die von B erbt, während sie auch in einem Setter überschrieben werden kann.

Verwandte Themen