Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/266.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 带有引用变量的C lambda委托调用方法_C#_Expression - Fatal编程技术网

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传递的,而您不会注意到它,因为它现在被装箱在对象[]中,并且原始值没有连接到该对象。我只有一个想法,我真的不知道这是否有可能。