泛型方法双参数类型推断问题:如何简化HasTypeAttribute调用?
为什么泛型方法无法自动推断第二个类型参数?如何实现预期调用方式?
这个问题其实戳中了C#泛型类型推断的一个关键规则,咱们一步步说清楚:
为什么当前代码无法推断TType?
你写的HasTypeAttribute<TAttribute, TType>(TType obj)方法,当尝试用HasTypeAttribute<SerializableAttribute>(instance)调用时,编译器会报错——这不是因为它不能推断TType,而是C#的泛型规则不允许「部分显式指定泛型参数」。
简单来说:
- 如果你的方法有多个泛型参数,要么完全让编译器推断所有参数(比如
Demo<T>(T obj)这种单参数场景),要么显式指定所有泛型参数。你不能只指定前面的,让编译器自动补全后面的——哪怕后面的参数理论上可以从方法参数推断出来。
调整泛型参数顺序也没用,因为规则是「只要显式指定了任意一个,就必须全部指定」,编译器不会跳过已指定的参数去推断剩下的。
怎么实现你想要的调用体验?
有两种方案,取决于你实际想检查的是编译时类型还是运行时类型:
方案1:用扩展方法(检查编译时类型)
把方法改成扩展方法,让编译器从调用者实例自动推断TType,你只需要显式指定TAttribute:
public static class TypeHelper { public static bool HasTypeAttribute<TAttribute, TType>(this TType obj) where TAttribute : Attribute { return typeof(TType).GetCustomAttribute<TAttribute>() != null; } }
调用方式完全符合你的预期:
MyClass instance = new MyClass(); instance.HasTypeAttribute<SerializableAttribute>();
这里TType会被编译器自动推断为MyClass,你只需要指定要检查的特性类型即可。
方案2:调整方法参数(检查运行时类型)
如果你想检查的是对象实际运行时类型上的特性,而不是编译时声明的类型,可以简化方法,去掉TType泛型参数:
public static class TypeHelper { public static bool HasTypeAttribute<TAttribute>(object obj) where TAttribute : Attribute { if (obj == null) throw new ArgumentNullException(nameof(obj)); return obj.GetType().GetCustomAttribute<TAttribute>() != null; } }
调用方式同样简洁:
MyClass instance = new MyClass(); TypeHelper.HasTypeAttribute<SerializableAttribute>(instance);
注意这个方案和原方法的区别:原方法检查的是TType(编译时类型)的特性,而这个方案检查的是对象实际类型的特性。比如如果instance被赋值给object变量,原方法会检查object的特性,而这个方案会检查MyClass的特性。
总结
你的设计本身没有问题,只是撞在了C#泛型推断的规则上。通过扩展方法(针对编译时类型)或者调整方法参数(针对运行时类型),都能实现你想要的简洁调用方式。
内容的提问来源于stack exchange,提问作者Thomas Flinkow
相关产品推荐
相关产品推荐

