C#派生类隐藏方法在泛型方法中失效,单元测试失败原因咨询
泛型与非泛型方法返回结果不一致的原因解析
using Microsoft.VisualStudio.TestTools.UnitTesting; namespace UnitTest1 { // 声明一些隐藏基类方法并实现接口的类 public interface IGet { string Get(); } public class GetA: IGet { public string Get() { return "a"; } } public class GetB: GetA { public new string Get() { return "b"; } } public static class GetUtil<T> where T : IGet { public static string Get(T aGetObject) { return aGetObject.Get(); } } public static class GetAUtil { public static string Get(GetA aGetObject) { return aGetObject.Get(); } } public static class GetBUtil { public static string Get(GetB aGetObject) { return aGetObject.Get(); } } [TestClass] public class NewUnitTest { // 验证泛型与非泛型方法返回结果一致 [TestMethod] public void TestGetInterfaceImplemetors() { var a = new GetA(); var b = new GetB(); Assert.AreEqual(GetAUtil.Get(a), GetUtil<GetA>.Get(a)); Assert.AreEqual(GetBUtil.Get(b), GetUtil<GetB>.Get(b)); //此处测试失败,原因何在? } } }
核心原因拆解
1. new关键字的本质:隐藏而非重写
GetB类里的public new string Get()只是隐藏了基类GetA的Get方法,不是重写。它的作用是:当变量的编译类型是GetB时,调用Get会触发这个新方法;但如果变量的编译类型是基类GetA或者接口IGet,调用的还是原来的基类实现。
2. 非泛型方法GetBUtil.Get(GetB)的执行逻辑
这个方法的参数是明确的GetB类型,编译器直接绑定到GetB类里用new定义的Get()方法,所以返回值是"b"。
3. 泛型方法GetUtil<GetB>.Get(T)的执行逻辑
泛型约束where T : IGet不仅是类型限制,还会影响编译器的方法绑定逻辑:
- 编译器在处理
aGetObject.Get()时,会优先依据接口IGet的定义来解析方法(因为约束保证了T必然实现IGet)。 - GetB并没有显式重新实现IGet接口的Get方法,它只是用
new隐藏了基类的方法。所以接口IGet的Get方法在GetB实例上,实际指向的还是继承自GetA的实现,最终返回"a"。
修复思路(可选)
如果想让泛型方法也返回"b",可以选以下任意一种方式:
- 给GetA的Get方法加上
virtual,GetB的Get方法改用override(真正的重写,支持多态); - 让GetB显式实现IGet接口的Get方法:
public class GetB: GetA, IGet { string IGet.Get() { return "b"; } public new string Get() { return "b"; } } - 移除泛型方法的
IGet约束,让编译器直接根据T的实际类型绑定方法。
内容的提问来源于stack exchange,提问作者Eduardo Rojas
相关产品推荐
相关产品推荐

