È possibile avere un ParameterExpression fuori?

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

Domanda

Voglio definire un'espressione Lambda con un parametro out . È possibile farlo?

Di seguito sono riportati frammenti di codice da un'app console C # .Net 4.0 che ho provato.

Come si può vedere in Procedura25, posso usare espressioni lambda per definire un delegato che ha un parametro di output, tuttavia, quando voglio usare espressioni di linq per fare lo stesso, il codice nella procedura 24 fallisce con:

System.ArgumentException was unhandled Message = ParameterExpression di tipo 'System.Boolean' non può essere utilizzato per il parametro delegato di tipo 'System.Boolean &' Source = System.Core

So che potrei usare un oggetto di classe input con un membro bool e restituire il valore al chiamante in quel modo, ma ero curioso di poter definire in qualche modo i parametri.

Grazie

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

MODIFICARE:

Ani, fantastico, grazie. Quindi la cosa fondamentale era chiamare MakeByRefType sul tipo di parametro.

Per la cronaca ecco uno snippet di codice che funziona sulla base del suggerimento di 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);

}

Risposta accettata

Hai bisogno di Type.MakeByRefType :

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

Nota che il tuo esempio di codice ha un ulteriore problema: il tuo corpo-espressione non è corretto - non restituisce un valore quando dovrebbe restituire un int per soddisfare il tipo di ritorno del tipo delegato.

Ecco un modo per correggerlo (come il tuo esempio di lambda):

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

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

Si noti inoltre che non si sta assegnando il parametro out all'interno dell'espressione. Expression.Lambda sta lasciando scappare, cosa che non mi aspettavo, ma hey, il BCL non deve seguire le stesse regole di C #!



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché