Est-il possible d'avoir une sortie ParameterExpression?

.net .net-4.0 c# expression-trees linq

Question

Je veux définir une expression Lambda avec un paramètre out . Est-il possible de le faire?

Vous trouverez ci-dessous des extraits de code provenant d'une application pour console C # .Net 4.0 que j'ai essayée.

Comme vous pouvez le constater dans Procédure25, je peux utiliser des expressions lambda pour définir un délégué doté d'un paramètre de sortie. Toutefois, lorsque je souhaite utiliser des expressions linq pour faire de même, le code de la procédure 24 échoue avec:

System.ArgumentException non gérée Message = ParameterExpression de type 'System.Boolean' ne peut pas être utilisée pour le paramètre de délégué de type 'System.Boolean &' Source = System.Core

Je sais que je pourrais utiliser un objet de classe d'entrée avec un membre bool et renvoyer la valeur à l'appelant de cette façon, mais j'étais curieux de pouvoir définir d'une manière ou d'une autre des paramètres.

Merci

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);
}

MODIFIER:

Ani, génial, merci. L'important était donc d'appeler MakeByRefType sur le type de paramètre.

Pour mémoire, voici un extrait de code qui fonctionne selon la suggestion d'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);

}

Réponse acceptée

Vous avez besoin de Type.MakeByRefType :

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

Notez que votre exemple de code présente un problème supplémentaire: votre corps d'expression n'est pas correct. Il ne renvoie pas de valeur alors qu'il devrait renvoyer un int pour satisfaire le type de retour du type délégué.

Voici un moyen de résoudre ce problème (comme dans votre exemple lambda):

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

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

Notez également que vous n'affectez pas le paramètre out à l'intérieur de l'expression. Expression.Lambda vous permet de vous en sortir, ce à quoi je ne m'attendais pas, mais la BCL n'a pas à suivre les mêmes règles que C #!



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow