C# 带有引用变量的C lambda委托调用方法
下面的代码仅适用于调用没有引用参数的方法C# 带有引用变量的C lambda委托调用方法,c#,expression,C#,Expression,下面的代码仅适用于调用没有引用参数的方法 public delegate void testD2(params object[] args); public static testD2 SetTestD2(MethodInfo method) { ParameterExpression param = Expression.Parameter(typeof(object[]), "args"); ParameterInfo[] paramsInfo = method.GetParame
public delegate void testD2(params object[] args);
public static testD2 SetTestD2(MethodInfo method)
{
ParameterExpression param = Expression.Parameter(typeof(object[]), "args");
ParameterInfo[] paramsInfo = method.GetParameters();
Expression[] argsExp = new Expression[paramsInfo.Length];
for (int i = 0; i < paramsInfo.Length; i++)
{
Expression index = Expression.Constant(i);
Type paramType = paramsInfo[i].ParameterType;
//??? ByRef removed from type, becuse Expression.Call with ByRef parametrs lead to compile error
if (paramType.IsByRef == true)
paramType = paramType.GetElementType();
//??? and for this reason is not change of parameters permanent
Expression paramAccessorExp = Expression.ArrayIndex(param, index);
Expression paramCastExp = Expression.Convert(paramAccessorExp, paramType);
argsExp[i] = paramCastExp;
}
var blockExp = Expression.Call(method, argsExp);
LambdaExpression result = Expression.Lambda(typeof(testD2), blockExp, param); //change in param?
return (testD2)result.Compile();
}
ref或out参数与params不兼容,我认为这是一种基本语言或运行时限制
要执行所需操作,可以编译为正确类型的强类型委托。调用可以创建正确的类型;与params object[]不同,可以有输出和引用参数。强类型委托是一种方法,但需要为各种方法编写额外的代码。这就是为什么我尝试使用常规函数来创建常规委托。
public delegate void testD2(params object[] args);
public static testD2 SetTestD2(MethodInfo method)
{
ParameterExpression param = Expression.Parameter(typeof(object[]), "args");
ParameterInfo[] paramsInfo = method.GetParameters();
Expression[] argsExp = new Expression[paramsInfo.Length];
for (int i = 0; i < paramsInfo.Length; i++)
{
Expression index = Expression.Constant(i);
Type paramType = paramsInfo[i].ParameterType;
//??? ByRef removed from type, becuse Expression.Call with ByRef parametrs lead to compile error
if (paramType.IsByRef == true)
paramType = paramType.GetElementType();
//??? and for this reason is not change of parameters permanent
Expression paramAccessorExp = Expression.ArrayIndex(param, index);
Expression paramCastExp = Expression.Convert(paramAccessorExp, paramType);
argsExp[i] = paramCastExp;
}
var blockExp = Expression.Call(method, argsExp);
LambdaExpression result = Expression.Lambda(typeof(testD2), blockExp, param); //change in param?
return (testD2)result.Compile();
}
对于关键字params,我认为如果函数被经典地调用为DelegateSomeFunc a,b,c,,那么就不会通过引用传递任何内容。但是,如果函数由数组调用,则参数通过引用传递
int k = 5;
string b = "aa";
object[] objArr = { k, b };
compiledObject2(k, b); //parameters passed by value
compiledObject2(objArr); //array passed by reference (params don't need create new array?)
例如,委托调用此函数
public static void TestMethod(ref int a, string text)
{
a = a * a;
}
从理论上讲,使用函数创建委托是可能的,但还有另一个问题-使用EXSPRESIONS parametrs数组调用函数,而不是使用表达式数组。
以上代码在原帖子中有一行
var blockExp = Expression.Call(method, argsExp);
但是argsExp可能无法返回由函数更改的参数。由于这个原因,我在局部表达式变量中写入输入参数,调用的函数可以更改,最后将更改后的值放入输入参数数组中
public static Class1.testD2 SetTestD2(System.Reflection.MethodInfo method)
{
ParameterExpression param = Expression.Parameter(typeof(object[]), "args"); // Expression.Parameter(typeof(object[]), "args");
BinaryExpression[] byExp=null;
Expression[] argsExp = GetArgExp(method.GetParameters(), param, ref byExp);
ParameterExpression xxx = Expression.Variable(typeof(int));
ParameterExpression yyy = Expression.Variable(typeof(string));
var blockExp =
Expression.Block( new[] { xxx, yyy } //variables
, Expression.Assign(xxx, argsExp[0])
, Expression.Assign(yyy, argsExp[1])
, Expression.Call(method, xxx, yyy)
, Expression.Assign(Expression.ArrayAccess(param, Expression.Constant(0)), Expression.Convert(xxx, typeof(object))) //change input param array
) ;
LambdaExpression result = Expression.Lambda(typeof(testD2), blockExp, param);
return (testD2)result.Compile();
}
该函数只是更改输入参数的一个示例。现在可以返回已更改的参数
MethodInfo mi = typeof(Class1).GetMethod("TestMethod");
var compiledObject2 = Class1.SetTestD2(mi);
int k = 5;
string b = "aa";
object[] objArr = { k, b };
compiledObject2(k, b); //no changes
compiledObject2(objArr); //objArr[0] changed
但我不知道是否可以修改创建委托的函数来创建一般委托。欢迎使用堆栈溢出。这里的大局是什么?你想用表达式树实现什么?您是否必须使用ref参数,或者是否可以从该方法返回适当的值?您必须使用该委托类型,还是可以使用与您试图调用的方法实际匹配的委托类型?如果没有更多的背景,就很难给出答案。有可能它实际上是由ref传递的吗?因为您使用的是params object[],所以我假设int 5被装箱并放入数组中。该装箱值现在与原始值无关。如果该装箱值通过ref传递,则k的基础值不会更改。这就是为什么我认为它实际上可能是通过ref传递的,而您不会注意到它,因为它现在被装箱在对象[]中,并且原始值没有连接到该对象。我只有一个想法,我真的不知道这是否有可能。