是否可以使用ParameterExpression?

cos*_*sta 11 .net c# linq .net-4.0 expression-trees

我想用out参数定义一个Lambda表达式.有可能吗?

以下是我尝试过的C#.Net 4.0控制台应用程序的代码片段.

正如您在Procedure25中看到的,我可以使用lambda表达式来定义具有输出参数的委托,但是,当我想使用linq表达式执行相同操作时,过程24中的代码将失败:

System.ArgumentException未处理Message = ParameterExpression类型'System.Boolean'不能用于'System.Boolean&'Source = System.Core类型的委托参数

我知道我可以使用带有bool成员的输入类对象并将值传递给调用者,但是如果我能以某种方式定义参数,我很好奇.

谢谢

static void Main(string[] args)
{
  Procedure25();
  Procedure24();
  Console.WriteLine("Done!");
  Console.ReadKey();
}

private delegate int Evaluate(string value, out bool usesVars);

private static void Procedure24()
{

  // This fails to compile:
  //Expression<Evaluate> x = (string val,  out bool usesSimVals) =>
  //{
  //  usesSimVals = true;
  //  Console.WriteLine(val);
  //  return 1;
  //};


  ParameterExpression valueParameter = Expression.Parameter(typeof (string));
  MethodCallExpression methodCall = Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(object) }), valueParameter);

  bool usesVars;
  ParameterExpression usesVarsParameter = Expression.Parameter(typeof (bool), "out usesVars");


  Expression.Lambda<Evaluate>(methodCall, valueParameter, usesVarsParameter).Compile()("test", out usesVars);
  Console.WriteLine(usesVars);

}

private static void Procedure25()
{
  Evaluate x = (string value, out bool vars) => { vars = true;
    Console.WriteLine(value);
                                                    return 1;
  };

  bool usesVars;
  x("test", out usesVars);
}
Run Code Online (Sandbox Code Playgroud)

编辑:

Ani,太棒了,谢谢.所以关键是在参数类型上调用MakeByRefType.

这里的记录是一个代码片段,根据Ani的建议工作:

private static void Procedure24()
{
  ParameterExpression valueParameter = Expression.Parameter(typeof (string));
  MethodCallExpression methodCall = Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(object) }), valueParameter);

  bool usesVars;
  ParameterExpression usesVarsParameter = Expression.Parameter(typeof (bool).MakeByRefType(), "out usesVars");

  Expression block = Expression.Block(methodCall, Expression.Assign(usesVarsParameter, Expression.Constant(true)), Expression.Constant(1));
  int result = Expression.Lambda<Evaluate>(block, valueParameter, usesVarsParameter).Compile()("test", out usesVars);
  Console.WriteLine("Result={0}, usesVars={1}", result, usesVars);

}
Run Code Online (Sandbox Code Playgroud)

Ani*_*Ani 8

你需要Type.MakeByRefType:

var usesVarsParameter = Expression.Parameter(typeof(bool).MakeByRefType(), "usesVars");
Run Code Online (Sandbox Code Playgroud)

请注意,您的代码示例还有一个问题:表达式主体不正确 - 当它应该返回一个值int以满足委托类型的返回类型时,它不返回值.

这是一种你可以解决的方法(就像你的lambda例子):

var body = Expression.Block(methodCall, Expression.Constant(1));

Expression.Lambda<Evaluate>(body, valueParameter, usesVarsParameter)
          .Compile()("test", out usesVars);
Run Code Online (Sandbox Code Playgroud)

另请注意,您没有out在表达式中分配参数.Expression.Lambda让你逃脱它,我没想到,但嘿,BCL不必遵循与C#相同的规则!