You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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();

关键说明

  1. 移除handler参数:因为已经持有dbTypeHandler实例,直接用Expression.Constant将其传入调用表达式即可,无需再作为委托参数。
  2. 类型转换处理:通过Expression.Convert把object类型的参数转换为当前handler对应的T类型,匹配SetValue方法的参数要求。
  3. 直接生成目标委托:使用泛型版本的Expression.Lambda直接创建Action<IDbDataParameter, object>类型的Lambda,编译后直接得到所需委托。

这样处理后,编译得到的委托可以直接接收IDbDataParameter和object类型的参数,内部自动完成类型转换并调用对应handler的SetValue方法。


内容的提问来源于stack exchange,提问作者user1814688

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 16:38:29