疑问:long?是否为结构体?Nullable<T>泛型方法调用为何表现为对象?
这是一个很典型的C#泛型约束和Nullable<T>特殊性的坑!你没误解struct的含义,但C#对where T : struct约束有个特殊规则——它会排除Nullable值类型,哪怕Nullable<T>本身确实是结构体类型。
为什么会出现这个现象?
你的泛型方法Get<T>(T id) where T : struct要求T是「非Nullable的值类型」,而long?本质是Nullable<long>。虽然Nullable<T>是结构体,但C#规范明确把它排除在struct约束的匹配范围之外。
当你调用Get(param2)时,编译器尝试推断T为long?,发现它不满足struct约束,就把这个泛型方法从候选重载里剔除了,最后只能匹配到Get(object)这个兜底重载,所以输出了"is object"。
怎么区分Nullable、普通值类型和object?
最清晰的方案是新增一个专门针对Nullable<T>的重载方法,让它优先匹配:
class GenController { // 匹配普通值类型 public void Get<T>(T id) where T : struct { Console.Write("is struct"); } // 匹配Nullable值类型(优先级更高) public void Get<T>(Nullable<T> id) where T : struct { Console.Write("is nullable struct"); } // 匹配引用类型(包括装箱的值类型) public void Get(object obj) { Console.Write("is object"); } }
这样调用时的结果会符合预期:
new GenController().Get(1234L)→ 匹配第一个方法,输出is structnew GenController().Get((long?)1234)→ 匹配第二个方法,输出is nullable structnew GenController().Get("test")→ 匹配第三个方法,输出is object
如果你不想单独加重载,也可以调整泛型约束为where T : ValueType(它包含Nullable<T>),再在方法内部区分类型:
public void Get<T>(T id) where T : ValueType { if (Nullable.GetUnderlyingType(typeof(T)) != null) { Console.Write("is nullable struct"); } else { Console.Write("is struct"); } }
不过这种方式不如新增重载直观,推荐优先使用第一种方案。
内容的提问来源于stack exchange,提问作者sinsedrix
相关产品推荐
相关产品推荐

