如何创建具有动态类型的 lambda 表达式
How to create a lambda expression with dynamic types
我的程序将在其 运行 时间内获取服务名称和方法名称,并且为了动态执行该方法,我正在创建一个基于 lambda 表达式的函数。
public static Func<object,object,object> CreateLambdaExpression2(string tService, string methodName)
{
var inputServiceType = Type.GetType(tService);
var methodInfo = inputServiceType.GetMethod(methodName);
var inputType = methodInfo.GetParameters().First().ParameterType;
var outputType = methodInfo.ReturnParameter.ParameterType;
var instance = Expression.Parameter(inputServiceType, "serviceInstance");
var input = Expression.Parameter(inputType, "inputData");
var call = Expression.Call(instance, methodInfo, input);
var lambdaFunc = Expression.Lambda<Func<object,object, object>>(call, instance, input).Compile(); //<= this line throws the error.
return lambdaFunc;
}
但它不会,它会在 运行 时间抛出错误
var compiledMethod = ServiceMapper.CreateLambdaExpression2(tService,"Get");
var serviceInstance = new TestDemoService();
var inputData = new TestDemoPersonRequest()
{
Id = 555
};
var result = compiledMethod(serviceInstance, inputData);
System.ArgumentException: 'ParameterExpression of type
'UnitTests.ITestDemoService' cannot be used for delegate parameter of
type 'System.Object''
有没有办法指定 Expression.Lambda 的类型?
Expression.Lambda<Func<object,object, object>>
到
Expression.Lambda<Func<inputServiceType ,inputType , outputType >>
您的表达式缺少类型转换。要使其编译,您需要明确地将 object
转换为 inputServiceType
等等。试试这个代码:
var objType = typeof(object);
var instance = Expression.Parameter(objType, "serviceInstance");
var input = Expression.Parameter(objType, "inputData");
var call = Expression.Call(
Expression.Convert(instance, inputServiceType), // convert first arg
methodInfo,
Expression.Convert(input, inputType)); // and second
var body = Expression.Convert(call, objType); // and even return type
var lambdaFunc = Expression.Lambda<Func<object, object, object>>(body, instance, input).Compile();
return lambdaFunc;
试试看here
编辑 你可以让它更安全:
public static Func<TService, TInput, TReturn>
CreateTypedLambdaExpression<TService, TInput, TReturn>(
string methodName)
{
var inputServiceType = typeof(TService);
var methodInfo = inputServiceType.GetMethod(methodName);
var inputType = typeof(TInput);
// now you need to check if TInput is equal to methodInfo.GetParameters().First().ParameterType
// same check for return type
var instance = Expression.Parameter(inputServiceType, "serviceInstance");
var input = Expression.Parameter(inputType, "inputData");
var call = Expression.Call(instance, methodInfo, input);
var lambdaFunc = Expression.Lambda<Func<TService, TInput, TReturn>>(call, instance, input);
return lambdaFunc.Compile();
}
用法:
var func = CreateTypedLambdaExpression<Program, bool, int>("TestMethod");
var result = func(service, false);
我的程序将在其 运行 时间内获取服务名称和方法名称,并且为了动态执行该方法,我正在创建一个基于 lambda 表达式的函数。
public static Func<object,object,object> CreateLambdaExpression2(string tService, string methodName)
{
var inputServiceType = Type.GetType(tService);
var methodInfo = inputServiceType.GetMethod(methodName);
var inputType = methodInfo.GetParameters().First().ParameterType;
var outputType = methodInfo.ReturnParameter.ParameterType;
var instance = Expression.Parameter(inputServiceType, "serviceInstance");
var input = Expression.Parameter(inputType, "inputData");
var call = Expression.Call(instance, methodInfo, input);
var lambdaFunc = Expression.Lambda<Func<object,object, object>>(call, instance, input).Compile(); //<= this line throws the error.
return lambdaFunc;
}
但它不会,它会在 运行 时间抛出错误
var compiledMethod = ServiceMapper.CreateLambdaExpression2(tService,"Get");
var serviceInstance = new TestDemoService();
var inputData = new TestDemoPersonRequest()
{
Id = 555
};
var result = compiledMethod(serviceInstance, inputData);
System.ArgumentException: 'ParameterExpression of type 'UnitTests.ITestDemoService' cannot be used for delegate parameter of type 'System.Object''
有没有办法指定 Expression.Lambda 的类型?
Expression.Lambda<Func<object,object, object>>
到
Expression.Lambda<Func<inputServiceType ,inputType , outputType >>
您的表达式缺少类型转换。要使其编译,您需要明确地将 object
转换为 inputServiceType
等等。试试这个代码:
var objType = typeof(object);
var instance = Expression.Parameter(objType, "serviceInstance");
var input = Expression.Parameter(objType, "inputData");
var call = Expression.Call(
Expression.Convert(instance, inputServiceType), // convert first arg
methodInfo,
Expression.Convert(input, inputType)); // and second
var body = Expression.Convert(call, objType); // and even return type
var lambdaFunc = Expression.Lambda<Func<object, object, object>>(body, instance, input).Compile();
return lambdaFunc;
试试看here
编辑 你可以让它更安全:
public static Func<TService, TInput, TReturn>
CreateTypedLambdaExpression<TService, TInput, TReturn>(
string methodName)
{
var inputServiceType = typeof(TService);
var methodInfo = inputServiceType.GetMethod(methodName);
var inputType = typeof(TInput);
// now you need to check if TInput is equal to methodInfo.GetParameters().First().ParameterType
// same check for return type
var instance = Expression.Parameter(inputServiceType, "serviceInstance");
var input = Expression.Parameter(inputType, "inputData");
var call = Expression.Call(instance, methodInfo, input);
var lambdaFunc = Expression.Lambda<Func<TService, TInput, TReturn>>(call, instance, input);
return lambdaFunc.Compile();
}
用法:
var func = CreateTypedLambdaExpression<Program, bool, int>("TestMethod");
var result = func(service, false);