如何在C#中始终调用类的最新重定义字段而非父类字段?
搞懂C#中
new关键字隐藏字段的问题,以及如何实现多态访问 这绝对是C#初学者常踩的坑!我来给你理清楚为什么你得到的是"A",以及怎么实现你想要的“始终调用最新重定义字段”的效果。
为什么你的代码输出"A"?
首先得明确:C#的字段不支持多态,new关键字在这里的作用只是「隐藏」父类的字段,而不是「重写」它。
看你的代码:
public static void Main(string[] args) { A test = new B(); Console.WriteLine(test.s); } public class A { public string s = "A"; } public class B : A{ public new string s = "B"; }
这里test的编译时类型是A,虽然它指向的是B的实例,但字段访问是静态绑定的——编译器会根据变量的编译时类型(也就是A)来查找字段,所以最终访问的是A类里的s,自然输出"A"。
说白了,子类B里的new string s是一个全新的字段,和父类A的s只是名字相同,完全是两个独立的东西。如果你把test改成B test = new B();,输出就会是"B",但这显然不是你想要的通用解决方案。
如何实现“始终调用最新重定义的成员”?
要实现这种多态的效果,你需要用虚拟属性+重写,因为属性的get/set本质是方法,而方法支持多态。
方案1:用虚拟属性直接返回值
这是最简洁的方式:
public static void Main(string[] args) { A test = new B(); Console.WriteLine(test.S); // 现在会输出"B" } public class A { // 定义虚拟属性 public virtual string S => "A"; } public class B : A{ // 重写父类的虚拟属性 public override string S => "B"; }
方案2:带字段存储的虚拟属性
如果需要在类内部修改这个值,可以结合私有字段:
public static void Main(string[] args) { A test = new B(); Console.WriteLine(test.S); // 输出"B" test.S = "Updated B"; Console.WriteLine(test.S); // 输出"Updated B" } public class A { protected string _s = "A"; public virtual string S { get => _s; set => _s = value; } } public class B : A{ // 可以选择直接修改父类的字段,或者重写属性用自己的字段 public B() { _s = "B"; } // 或者重写属性使用子类自己的字段: // private string _bS = "B"; // public override string S { // get => _bS; // set => _bS = value; // } }
核心总结
- 字段没有多态性,
new只是隐藏同名字段,访问时看变量的编译时类型 - 要实现“不管引用类型是什么,都调用实例实际类型的成员”,必须用虚拟成员(方法/属性)+ override重写
- 这是C#面向对象多态的基础特性,记住:字段不参与多态,只有方法(包括属性的get/set)支持多态
内容的提问来源于stack exchange,提问作者Meowxiik
相关产品推荐
相关产品推荐

