You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:34:12