Возможно ли получить параметр ParameterExpression?

Я хочу определить выражение Lambda с параметром out. Можно ли это сделать?

Ниже приведены фрагменты кода из консольного приложения С#.Net 4.0, которое я пробовал.

Как вы можете видеть в процедуре25, я могу использовать лямбда-выражения для определения делегата, у которого есть выходной параметр, однако, когда я хочу использовать выражения linq, чтобы сделать то же самое, код в процедуре 24 не работает:

Исправление System.ArgumentException было необработанным Message = ParameterExpression типа "System.Boolean" не может использоваться для параметра делегирования типа 'System.Boolean &' Источник = 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);
}

EDIT:

Ани, потрясающе, спасибо. Итак, главное было вызвать 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);

}

Ответ 1

Вам нужно Type.MakeByRefType:

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

Обратите внимание, что в вашем примере кода есть дополнительная проблема: ваше тело выражения неверно - оно не возвращает значение, когда оно должно возвращать int для удовлетворения возвращаемого типа типа делегата.

Здесь вы можете исправить это (например, ваш пример лямбда):

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

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

Также обратите внимание, что вы не назначаете параметр out внутри выражения. Expression.Lambda позволяет вам уйти от него, чего я не ожидал, но, эй, BCL не должен следовать тем же правилам, что и С#!