我有一种情况,我希望在具有默认值的派生类中使普通属性成为只读。 我通过以下方式为此目的使用关键字 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
更新:
我添加了新答案作为第三种选择,可能是最好的。
答案 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; }
}
}