使用new和override将BaseClass属性更改为DerivedClass中的readonly

时间:2017-02-06 10:09:16

标签: c# inheritance override readonly

我有一种情况,我希望在具有默认值的派生类中使普通属性成为只读。 我通过以下方式为此目的使用关键字 new

public abstract class BaseClass
{
    public virtual string SomeInfo { get; set; }
}
public class DerivedClass1 : BaseClass
{
    public new string SomeInfo => "ChildInfo1"; // C# 6.0 equivalent of { get { return "ChildInfo1"; } }
}

它工作正常,new DerivedClass1().SomeInfo无法分配 - 它只是readonly。我知道可以通过基类访问它:

BaseClass b1 = new DerivedClass1();
b1.SomeInfo = "ChildInfo1 changed";

我只是想让用户无法意外地改变它,并且通过基类它将是有目的的,在这种情况下它是可以接受的。

但是,如果Derived类是这样的:

public class DerivedClass2 : BaseClass
{
    public override string SomeInfo => "ChildInfo2";
}

然后这个属性是可访问的,你可以看似改变它但它不会改变,我想理解为什么?

var d2 = new DerivedClass2();
d2.SomeInfo = "ChildInfo2 changed";
Console.WriteLine(d2.SomeInfo); // output: ChildInfo2

更新:
我添加了新答案作为第三种选择,可能是最好的。

3 个答案:

答案 0 :(得分:1)

在您的基础课程中

public virtual string SomeInfo { get; set; }

这只是一个很好的定义:

private string _someInfo;
public string SomeInfo
{
  get {return _someInfo;}
  set {_someInfo = value;}
}

如果使用Expression-Bodied属性覆盖它,则使用

覆盖get属性
public string SomeInfo
{
  get {return "ChildInfo2";}
}

但是你没有覆盖set属性,所以你仍然可以设置私有变量,但它不会改变其他任何东西。

如果你看一下你的第一个例子:

BaseClass b1 = new DerivedClass1();
b1.SomeInfo = "ChildInfo1 changed";

它发生完全相同的事情,你可以设置属性,因为基类确实有setter并设置一个私有变量,但如果你尝试输出SomeProperty的值,你会看到它没有被改变,仍然是“ChildInfo1” “

答案 1 :(得分:0)

在这种情况下你应该避免使用“新”。 相反,在您的派生类中定义一个readonly属性:

public override string SomeInfo { get { return "ChildInfo"; } }

您仍然可以设置您的属性,但它始终会返回默认值“ChildInfo”。

答案 2 :(得分:0)

我现在已经做了第三个选项,可能是最好的,在Constructor中设置默认值。 感谢@MatthewWatson提请注意LSP和@MaksimSimkin的解释。

public abstract class BaseClass
{
    public string SomeInfo { get; set; }
}

public class DerivedClass1 : BaseClass
{
    public DerivedClass1()
    {
        base.SomeInfo = "ChildInfo1";
    }
    public new string SomeInfo => base.SomeInfo;
}

当从 DerivedClass 访问时,这使得 SomeInfo readOnly,并且如果通过 BaseClass 访问它,则它是可编辑的并且定期更改,并且从两个班级。所以没有'未知'的行为。

PS对于旧版本的C#,这是等效的:

public abstract class BaseClass
{
    protected string _someInfo;
    public string SomeInfo
    {
        get { return _someInfo; }
        set { _someInfo = value; }
    }
}

public class DerivedClass1 : BaseClass
{
    public DerivedClass1()
    {
        _someInfo = "ChildInfo1";
    }
    public new string SomeInfo
    {
        get { return _someInfo; }
    }
}