关于c#:覆盖获取,但未设置


Override Get, But Not Set

我有一个抽象类,它定义了一个get,而不是set,因为就抽象类而言,它只需要一个get

1
2
3
4
5
public abstract BaseClass
{
  public abstract double MyPop
  {get;}
}

但是,在一些派生类中,我需要一个set属性,因此我正在研究这个实现

1
2
3
4
5
public class DClass: BaseClass
{
  public override double MyPop
  {get;set;}
}

问题是,我有一个编译错误,说

*.set: cannot override because *. does not have an overridable set accessor.

尽管我认为上述语法是完全合法的。

对此有什么想法吗?解决方法,或者为什么是这样?

编辑:我能想到的唯一方法是把getset都放在抽象类中,如果调用set,并且不需要,让子类抛出NotImplementedException。这是我不喜欢的,还有一种特殊的设置方法。


一个可能的答案是重写getter,然后实现一个单独的setter方法。如果不希望在基中定义属性setter,则没有其他许多选项。

1
2
3
4
5
6
7
8
9
public override double MyPop
{
    get { return _myPop; }
}

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


做你想做的事是不可能的。必须在抽象属性中定义setter,否则将无法正确重写它。

唯一我知道在哪里定义getter和实现getter/setter的情况是使用接口:

1
2
3
4
5
6
7
8
9
public interface IBaseInterface
{
    double MyPop { get; }
}

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


C 6.0中的新功能:

如果只在构造函数中调用setter,则可以使用只读属性解决此问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;}
}


如果BaseClass在您自己的代码库中,那么您可以执行以下操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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)等中创建公共方法。域模型的类设计应该清楚或说明为什么不能直接在基类中设置属性,以及为什么可以在派生类中这样做。


你确定如果你找到一种方法去做你想做的事情会是一个好的设计吗?

它将允许子类的对象进行父类对象无法进行的状态更改。这不会违反里斯科夫替代原则吗?


这是不可能的原因,因为参数是通过c_"魔术师化"而存在的。定义参数时,C创建隐式getter和setter操作的私有字段。如果基类中没有setter,则无法从子类中写入的方法更改此变量(因为私有标志甚至禁止子类访问它)。通常情况下,它使用基类的隐式setter。

如果不是所有的子类都能做到,我不建议将集合放在基类中,因为这违背了多态编程的整个原则(抽象类中定义的任何抽象方法都必须由子类实现)。如其他答案所述,创建一个特殊的setter方法可能是最好的方法。


你可以这样做:

埃多克斯1〔2〕

使用testderived将具有您要查找的功能。从这个方法中我能看到的唯一缺点是,您必须在TestDerivedHelper中实现每个抽象方法,但它稍后会提供更多的控制。

希望这有帮助。;)


即使这条线是旧的,我也在提出我的解决方案,以防它能帮助别人。它不是我自己的,而是基于其他主题的答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
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; } }
}

此解决方案为需要修改访问器的每个此类属性添加一行额外的代码。但是,外部可见性没有变化,并且提供了所需的功能。


围攻

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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); }
    }
}

Using TestDerived will have the functionality you're looking for. The
only drawback I can see from this method is that you have to implement
every abstract method in TestDerivedHelper, but it gives you more
control later.

我使用这种方法,并为我很好地工作。此外,我还将"testderivedHelper"类抽象为抽象类,然后必须在"testderived"类上实现所有方法。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
}

如果需要从DClass外部设置属性,那么最好将setter放入基类。


编辑:

好吧,我可能对这个回答很仓促,但我现在已经多考虑了。

必须使用抽象基类吗?如果不需要,请尝试以下操作:

1
2
3
4
5
6
7
8
9
public interface ISomeRelevantName
{
    double MyPop { get; }
}

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


不能重写set访问器,因为基类没有定义set访问器。

您可以使用new关键字隐藏基类实现,但这可能不是您想要的。


为什么不在具有私有setter的基类中拥有一个属性,然后在需要setter的子类中重写它并将其公开呢?