如何将IDbTypeHandler<T>的SetValue转为Action<IDbDataParameter,object>类型Lambda表达式
问题描述
我有多个继承自IDbTypeHandler<T>的子类,想把这些子类里的SetValue方法转换成Lambda表达式,最终得到Action<IDbDataParameter, object>类型的委托。
相关接口定义
public interface IDbTypeHandler { }
public interface IDbTypeHandler<T> : IDbTypeHandler { void SetValue(IDbDataParameter parameter, T value); }
子类示例
internal class UniqueidentifierUlIdHandler : IDbTypeHandler<UlId> { public void SetValue(IDbDataParameter parameter, UlId value) { parameter.Value = value.ToByteArray(); } }
internal class Char1Handler : IDbTypeHandler<bool> { public void SetValue(IDbDataParameter parameter, bool value) { parameter.Value = value; } }
已尝试的代码
我写了下面的代码尝试生成Lambda表达式:
if (!TryGetValue("Key", out IDbTypeHandler dbTypeHandler)) { return false; } var t = dbTypeHandler.GetType(); var itf = t.GetInterfaces().SingleOrDefault(i => i.IsGenericType); var xx = itf.GenericTypeArguments[0]; var p0 = Expression.Parameter(t); var p1 = Expression.Parameter(typeof(IDbDataParameter)); var p2 = Expression.Parameter(xx); var method = t.GetMethod("SetValue"); Type delegateType = typeof(Action<,,>).MakeGenericType(t, typeof(IDbDataParameter), xx); var lambda = Expression.Lambda(delegateType, Expression.Call(p0, method, p1, p2), new[] { p0, p1, p2 });
现在生成的Lambda编译后返回Delegate类型,但我需要的是Action<IDbDataParameter,object>类型。我知道要在创建Lambda前做类型转换,但不知道具体怎么操作。
解决方案
要得到目标类型的委托,需要调整表达式树的构建逻辑,核心是处理object到具体T的类型转换,同时直接复用已有的dbTypeHandler实例,不需要将其作为委托参数传入。修改后的代码如下:
if (!TryGetValue("Key", out IDbTypeHandler dbTypeHandler)) { return false; } var handlerType = dbTypeHandler.GetType(); var genericInterface = handlerType.GetInterfaces() .Single(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDbTypeHandler<>)); var valueType = genericInterface.GenericTypeArguments[0]; // 定义Action的两个参数:IDbDataParameter和object var paramParam = Expression.Parameter(typeof(IDbDataParameter), "parameter"); var valueParam = Expression.Parameter(typeof(object), "value"); // 将object类型的value转换为当前handler对应的T类型 var convertedValue = Expression.Convert(valueParam, valueType); // 获取IDbTypeHandler<T>接口中的SetValue方法 var setValueMethod = genericInterface.GetMethod("SetValue"); // 构建调用表达式:用已有的dbTypeHandler实例调用SetValue,传入参数和转换后的值 var callExpr = Expression.Call(Expression.Constant(dbTypeHandler), setValueMethod, paramParam, convertedValue); // 直接生成Action<IDbDataParameter, object>类型的Lambda并编译 var lambda = Expression.Lambda<Action<IDbDataParameter, object>>(callExpr, paramParam, valueParam); Action<IDbDataParameter, object> action = lambda.Compile();
关键说明
- 移除handler参数:因为已经持有
dbTypeHandler实例,直接用Expression.Constant将其传入调用表达式即可,无需再作为委托参数。 - 类型转换处理:通过
Expression.Convert把object类型的参数转换为当前handler对应的T类型,匹配SetValue方法的参数要求。 - 直接生成目标委托:使用泛型版本的
Expression.Lambda直接创建Action<IDbDataParameter, object>类型的Lambda,编译后直接得到所需委托。
这样处理后,编译得到的委托可以直接接收IDbDataParameter和object类型的参数,内部自动完成类型转换并调用对应handler的SetValue方法。
内容的提问来源于stack exchange,提问作者user1814688
相关产品推荐
相关产品推荐

