Introduzionedinamicamente creare l'oggetto utilizzando la riflessione, i metodi e lambda incatenati espressioni
La mia applicazione crea un'istanza di un oggetto utilizzando il metodo di concatenamento in modo che viene generato e configurato in questo modo:
var car = new Car("Ferrari").Doors(2).OtherProperties(x = x.Color("Red"));
Problema
Ho un requiremen Per generare dinamicamente questo oggetto in fase di runtime, i metodi concatenati necessari per la configurazione verranno determinati in fase di runtime, quindi tutto deve essere assemblato dinamicamente al volo. In passato ho usato la riflessione per creare oggetti semplici come new Car("Ferrari", 2, "Red")
- Mi piace - ma mai niente con metodi concatenati contenenti espressioni lambda come parametri - questi due fattori mi hanno davvero bloccato. Ho esaminato gli alberi di espressione e credo che questo sia parte della soluzione per creare i parametri di espressione dinamica ma sono totalmente bloccato cercando di capire come cucirli insieme alla riflessione per creare l'oggetto di base e i metodi concatenati aggiuntivi.
ringraziamento e apprezzamento
in anticipo per il tempo dedicato a guardare il mio problema e per qualsiasi consiglio o informazioni che potrebbe essere in grado di fornire.
UPDATE: Conclusione
Molte grazie a dasblinkenlight e Jon Skeet per le loro risposte. Ho scelto la risposta di dasblinkenlight perché il suo esempio di codice mi ha messo fuori gioco immediatamente. Per il metodo di concatenamento ho fondamentalmente usato lo stesso approccio di ciclo nella risposta accettata, quindi non ripeterò quel codice ma sotto è il codice che ho scritto per convertire dinamicamente le chiamate del metodo dell'albero di espressione in delegati di azione che potrebbero essere eseguiti tramite la riflessione Invoke()
come delineato nella risposta di dasblinkenlight. Questo, come ha sottolineato Jon, era davvero il nocciolo del problema.
Classe di supporto per memorizzare i metadati del metodo.
public struct Argument
{
public string TypeName;
public object Value;
}
public class ExpressionTreeMethodCall
{
public string MethodName { get; set; }
public IList<Argument> Arguments { get; set; }
public ExpressionTreeMethodCall()
{
Arguments = new List<Argument>();
}
}
Metodo statico per assemblare una chiamata di metodo espressione lambda e poi tornare come un delegato azione da eseguire altrove (passato come argomento al Invoke()
nel mio caso).
public static Action<T> ConvertExpressionTreeMethodToDelegate<T>(ExpressionTreeMethodCall methodData)
{
ParameterExpression type = Expression.Parameter(typeof(T));
var arguments = new List<ConstantExpression>();
var argumentTypes = new List<Type>();
foreach (var a in methodData.Arguments)
{
arguments.Add(Expression.Constant(a.Value));
argumentTypes.Add(Type.GetType(a.TypeName));
}
// Creating an expression for the method call and specifying its parameter.
MethodCallExpression methodCall = Expression.Call(type, typeof(T).GetMethod(methodData.MethodName, argumentTypes.ToArray()), arguments);
return Expression.Lambda<Action<T>>(methodCall, new[] { type }).Compile();
}
Molte grazie das .. quindi utilizzando il codice fornito - potrebbero dell'oggetto d'azione "makeRed" essere memorizzati in "chainedArgs" ed eseguiti durante la "Invoke()" chiamata durante il ciclo di concatenamento? – mmacneil007
@ mmacneil007 Assolutamente, questa è l'idea. 'L'azione' è un delegato che può essere memorizzato in uno degli array all'interno dell'array 'chainedArgs' degli array, da passare al suo metodo corrispondente (nel tuo caso, sarebbe' OtherProperties'). –
dasblinkenlight
Eccellente, credo che questo mi abbia messo sulla strada giusta. Sto ancora avvolgendo la mia mente intorno agli alberi di espressione ma penso che l'approccio che hai delineato qui dovrebbe fare il trucco. Grazie ancora! – mmacneil007