如何基于属性类型通过反射生成通用C# Expression并调用泛型方法
问题描述
我需要针对自定义类的公共属性,动态调用以下泛型方法FuncToCall:
public SomeClass<TEnt, TDto> FuncToCall<TEntProp, TDtoProp>( string alias, Expression<Func<TEnt, TEntProp>> fromEntity, Expression<Func<TDto, TDtoProp>> toDto) { ... }
以User类为例,需分别对UserID(Guid类型)和UserName(string类型)调用该方法:
public class User { public Guid UserID { get; set; } public string UserName { get; set; } }
当前代码因硬编码Guid类型可运行,但需修改为根据属性实际类型动态生成对应表达式,而非固定写死类型。现有代码如下:
public static SomeClass<TEnt, TDto> BuildDynamic<TEnt, TDto>(this SomeClass<TEnt, TDto> cmp) where TEnt : class { var properties = typeof(TEnt).GetProperties(BindingFlags.Public | BindingFlags.Instance).Select(x => new { x.Name, x.PropertyType }).ToList(); foreach (var prop in properties) { string propName = prop.Name; // 属性名 Type typ = prop.PropertyType; // 属性类型(关键) Type funcType = typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(typeof(TEnt), typ)); ParameterExpression paramTEnt = Expression.Parameter(typeof(TEnt), "e"); MemberExpression propTEnt = Expression.Property(paramTEnt, propName); Expression<Func<TEnt, Guid>> expTEnt = Expression.Lambda<Func<TEnt, Guid>>(propTEnt, paramTEnt); // 硬编码Guid ParameterExpression paramTDto = Expression.Parameter(typeof(TDto), "r"); MemberExpression propTDto = Expression.Property(paramTDto, propName); Expression<Func<TDto, Guid>> expTDto = Expression.Lambda<Func<TDto, Guid>>(propTDto, paramTDto); // 硬编码Guid cmp.FuncToCall(propName, expTEnt, expTDto); } return null; }
解决方案
核心思路是通过反射动态生成泛型表达式树、调用泛型方法,替代硬编码的类型参数。修改后的代码如下:
public static SomeClass<TEnt, TDto> BuildDynamic<TEnt, TDto>(this SomeClass<TEnt, TDto> cmp) where TEnt : class { var properties = typeof(TEnt).GetProperties(BindingFlags.Public | BindingFlags.Instance); // 获取FuncToCall的泛型方法定义 var funcToCallMethod = typeof(SomeClass<TEnt, TDto>).GetMethod(nameof(SomeClass<TEnt, TDto>.FuncToCall)) ?? throw new InvalidOperationException("未找到FuncToCall方法"); foreach (var prop in properties) { string propName = prop.Name; Type entPropType = prop.PropertyType; // 确保TDto中存在同名属性,获取其类型 var dtoProp = typeof(TDto).GetProperty(propName) ?? throw new InvalidOperationException($"TDto中不存在属性{propName}"); Type dtoPropType = dtoProp.PropertyType; // 构建Entity侧的表达式树 ParameterExpression entParam = Expression.Parameter(typeof(TEnt), "e"); MemberExpression entPropExpr = Expression.Property(entParam, propName); Type entFuncType = typeof(Func<,>).MakeGenericType(typeof(TEnt), entPropType); var entExpr = typeof(Expression) .GetMethod(nameof(Expression.Lambda), new[] { typeof(Expression), typeof(ParameterExpression[]) }) ?.MakeGenericMethod(entFuncType) .Invoke(null, new object[] { entPropExpr, new[] { entParam } }); // 构建Dto侧的表达式树 ParameterExpression dtoParam = Expression.Parameter(typeof(TDto), "r"); MemberExpression dtoPropExpr = Expression.Property(dtoParam, propName); Type dtoFuncType = typeof(Func<,>).MakeGenericType(typeof(TDto), dtoPropType); var dtoExpr = typeof(Expression) .GetMethod(nameof(Expression.Lambda), new[] { typeof(Expression), typeof(ParameterExpression[]) }) ?.MakeGenericMethod(dtoFuncType) .Invoke(null, new object[] { dtoPropExpr, new[] { dtoParam } }); // 动态调用泛型版FuncToCall var genericFuncToCall = funcToCallMethod.MakeGenericMethod(entPropType, dtoPropType); genericFuncToCall.Invoke(cmp, new object[] { propName, entExpr, dtoExpr }); } return cmp; }
关键说明
- 获取泛型方法元数据:先拿到
FuncToCall的泛型定义,后续通过MakeGenericMethod生成对应属性类型的具体方法实例。 - 动态生成表达式树:通过反射调用
Expression.Lambda的泛型重载,传入运行时确定的属性类型,替代硬编码的泛型参数。 - 兼容Dto属性类型:单独获取TDto的属性类型,确保
FuncToCall的两个泛型参数TEntProp和TDtoProp与实际属性类型匹配。 - 反射执行调用:生成对应属性类型的
FuncToCall实例后,通过反射完成方法调用。
内容的提问来源于stack exchange,提问作者T Sl
相关产品推荐
相关产品推荐

