C#中List<object>调用AssertThat为何匹配泛型回退重载?
为什么C#泛型方法重载会匹配到回退方法?
先看你定义的两个泛型方法:
public static EnumerableAssertions<T> AssertThat<T>(IEnumerable<T> collection) { Debug.WriteLine("Enumerable!"); return new EnumerableAssertions<T>(collection); } public static ObjectAssertions<T> AssertThat<T>(T value) where T : class { Debug.WriteLine("Generic fallback!"); return new ObjectAssertions<T>(value); }
当调用AssertThat(list)(list是List<object>类型)时,编译器选择第二个重载的核心原因是C#重载决议的优先级规则:
- 对于第二个重载
AssertThat<T>(T value),编译器可以直接推断T = List<object>,此时参数类型List<object>和传入的变量类型完全一致,属于精确匹配。 - 对于第一个重载
AssertThat<T>(IEnumerable<T>),编译器推断T = object,但传入的List<object>需要隐式转换为IEnumerable<object>(接口),这属于转换匹配。
在C#的重载决议逻辑中,精确匹配的优先级远高于需要隐式转换的匹配,所以编译器会优先选择第二个泛型回退方法。
你添加List<T>的精确重载后能匹配,是因为那个重载的参数类型和传入的List<object>完全一致,优先级最高,但显然没必要为所有实现IEnumerable<T>的类型都加重载。
解决办法
不需要新增重载,只需要在调用时显式指定类型参数,引导编译器选择第一个重载:
List<object> list = null; AssertThat<object>(list); // 此时会匹配接收IEnumerable<T>的重载
这样指定T=object后,第一个重载的参数是IEnumerable<object>,第二个重载的参数是object,此时List<object>转换为IEnumerable<object>的优先级高于转换为object,编译器就会选择第一个重载。
内容的提问来源于stack exchange,提问作者Oliver Saggau
相关产品推荐
相关产品推荐

