Einführungdynamisch erstellen Objekt mit Reflexion, angekettet Methoden und Lambda-Ausdrücke
Meine Anwendung ein Objekt mit der Methode Verkettungs instanziiert, so dass es erzeugt wird und so konfiguriert ist, wie so:
var car = new Car("Ferrari").Doors(2).OtherProperties(x = x.Color("Red"));
Problem
Ich habe eine Voraussetzung t Um dieses Objekt zur Laufzeit dynamisch zu erzeugen, werden die zur Konfiguration benötigten verketteten Methoden zur Laufzeit ermittelt, so dass alles dynamisch im laufenden Betrieb zusammengestellt werden muss. Ich habe Reflektion in der Vergangenheit verwendet, um einfache Objekte wie new Car("Ferrari", 2, "Red")
zu erstellen - ich bin damit cool - aber nie etwas mit verketteten Methoden, die Lambda-Ausdrücke als Parameter enthalten - diese beiden Faktoren haben mich wirklich fest im Griff. Ich habe mir die Ausdrucksbäume angesehen und glaube, dass dies ein Teil der Lösung ist, um die dynamischen Ausdrucksparameter zu erstellen, aber ich bin total dabei, herauszufinden, wie man das zusammen mit der Reflexion zum Grundobjekt und den zusätzlichen verketteten Methoden zusammenfügt.
Dank und Anerkennung
im Voraus für die Zeit nehmen, um mein Problem zu suchen und für jede Anleitung oder Informationen, die Sie liefern können.
UPDATE: Fazit
Vielen Dank an dasblinkenlight und Jon Skeet für ihre Antworten. Ich habe dasblinkenlight's Antwort ausgewählt, weil sein Code-Sample mich sofort losgelöst hat. Für die Methodenverkettung habe ich grundsätzlich den gleichen Schleifenansatz in der akzeptierten Antwort verwendet, also werde ich diesen Code nicht wiederholen, aber unten ist der Code, den ich geschrieben habe, um Ausdruckbaummethodenaufrufe dynamisch in Aktionsdelegaten umzuwandeln, die dann wie beschrieben über die Reflektion Invoke()
ausgeführt werden könnten in dasblinkenlight's Antwort. Dies war, wie Jon betonte, wirklich der Kern des Problems.
Hilfsklasse zum Speichern von Methodenmetadaten.
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>();
}
}
Statische Methode einen Lambda-Ausdruck Methodenaufruf zu montieren und sie dann wieder als Aktionsdelegate wird an anderer Stelle ausgeführt (als Argument an Invoke()
in meinem Fall).
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();
}
Vielen Dank das .. so Ihre bereitgestellt Code - könnte das „makeRed“ Aktionsobjekt während des „Invoke()“ Anrufs in „chainedArgs“ und ausgeführt gespeichert wird während die Kettenschleife? – mmacneil007
@ mmacneil007 Absolut, das ist die Idee. 'Aktion' ist ein Delegat, das in einem der Arrays innerhalb des 'chainedArgs' Arrays von Arrays gespeichert werden kann, um es an die entsprechende Methode zu übergeben (in Ihrem Fall wäre das' OtherProperties'). –
dasblinkenlight
Ausgezeichnet, ich glaube, das hat mich auf den richtigen Weg gebracht. Ich wickle meinen Kopf immer noch um die Bäume herum, aber ich denke, der Ansatz, den Sie hier skizziert haben, sollte den Zweck erfüllen. Danke noch einmal! – mmacneil007