如何实现仅指定TType即可调用反射获取DescriptionAttribute的泛型方法?
问题描述
我定义了如下类:
public class Demo { [Description("Hello World!")] public int SomeProp { get; set; } }
为了获取属性的Description特性值,我写了下面这个泛型方法:
public string? GetDescription<TType, TProperty>(Expression<Func<TType, TProperty>> expression) where TType : class { var memberName = ((MemberExpression)expression.Body).Member.Name; var description = typeof(TType).GetMember(memberName).First() .GetCustomAttribute<DescriptionAttribute>() ?.Description; return description; }
目前调用的时候必须同时指定两个泛型参数:
var description = GetDescription<Demo, string>(x => x.SomeProp);
但我希望能简化成只指定TType的调用方式,让编译器自动推断属性类型:
var description = GetDescription<Demo>(x => x.SomeProp); // 不需要指定TProperty
现在不指定TProperty就会编译报错:“Using the generic method requires 2 type arguments”,请问该怎么实现这种调用方式?
解决方案
方案一:利用类型推断移除不必要的泛型参数
你的方法逻辑里其实根本没用到TProperty类型,只是需要通过表达式定位到属性成员。可以把表达式参数改成Expression<Func<TType, object>>,这样编译器会自动处理值类型的装箱操作,同时只需要显式指定TType:
public string? GetDescription<TType>(Expression<Func<TType, object>> expression) where TType : class { MemberExpression memberExpr; // 处理值类型装箱时的表达式包装(此时Body是UnaryExpression) if (expression.Body is UnaryExpression unaryExpr) { memberExpr = (MemberExpression)unaryExpr.Operand; } else { memberExpr = (MemberExpression)expression.Body; } var memberName = memberExpr.Member.Name; var description = typeof(TType).GetMember(memberName).First() .GetCustomAttribute<DescriptionAttribute>() ?.Description; return description; }
现在就能按你想要的方式调用了:
var description = GetDescription<Demo>(x => x.SomeProp);
方案二:拆分泛型参数到层级结构
如果一定要保留TProperty的泛型约束,可以用一个辅助类拆分泛型参数,让TType显式指定,TProperty通过后续方法自动推断:
// 辅助类,用于承载属性表达式的推断 public class DescriptionGetter<TType> where TType : class { public string? For<TProperty>(Expression<Func<TType, TProperty>> expression) { var memberName = ((MemberExpression)expression.Body).Member.Name; var description = typeof(TType).GetMember(memberName).First() .GetCustomAttribute<DescriptionAttribute>() ?.Description; return description; } } // 入口方法,只需要指定TType public DescriptionGetter<TType> GetDescription<TType>() where TType : class { return new DescriptionGetter<TType>(); }
调用方式变成:
var description = GetDescription<Demo>().For(x => x.SomeProp);
原方法无法推断的原因
C#的泛型类型推断规则是:要么完全通过方法参数自动推断所有泛型参数,要么显式指定全部泛型参数。当你手动指定了其中一个泛型参数(TType),编译器就会要求你指定所有剩余的泛型参数,不会再自动推断TProperty。所以必须通过上述方式打破这个限制。
内容的提问来源于stack exchange,提问作者lonix
相关产品推荐
相关产品推荐

