WprowadzenieDynamicznie tworzenie obiektu za pomocą refleksji, przykuty metody i lambda wyrażeń
Moja aplikacja tworzy instancję obiektu za pomocą metody łańcuchowym więc jest generowany i skonfigurowany tak:
var car = new Car("Ferrari").Doors(2).OtherProperties(x = x.Color("Red"));
Problem
Mam wymagającego t dynamicznie generować ten obiekt w środowisku wykonawczym - metody łańcuchowe potrzebne do konfiguracji zostaną określone w czasie wykonywania, więc wszystko musi być dynamicznie montowane w locie. Używałem w przeszłości refleksów do tworzenia prostych obiektów, takich jak new Car("Ferrari", 2, "Red")
- jestem z tym fajna - ale nigdy nic z przykutymi metodami zawierającymi wyrażenia lambda jako parametry - te dwa czynniki naprawdę mnie zablokowały. Przyjrzałem się drzewom ekspresji i wierzę, że jest to część rozwiązania do tworzenia parametrów dynamicznego wyrażania, ale całkowicie utknąłem próbując wymyślić, jak połączyć to z odbiciem, aby utworzyć obiekt podstawowy i dodatkowe metody łańcuchowe.
Dzięki i Wrażenia
z góry za poświęcenie czasu, aby spojrzeć na mojego problemu i żadnych wskazówek lub informacji może być w stanie zapewnić.
UPDATE: Zawarcie
Wiele dzięki dasblinkenlight i Jon Skeet na ich odpowiedzi. Wybrałem odpowiedź dasblinkenlight, ponieważ jego próbka kodu wyłączyła mnie natychmiast. Dla metody łańcuchowej użyłem zasadniczo tego samego podejścia do pętli w zaakceptowanej odpowiedzi, więc nie powtórzę tego kodu, ale poniżej jest kod, który napisałem, aby dynamicznie konwertować wywołania metod drzewa wyrażeń do delegatów akcji, które mogłyby następnie zostać wykonane poprzez odbicie Invoke()
jak opisano w odpowiedzi dasblinkenlight. To, jak zauważył Jon, było sednem problemu.
Klasa pomocnicza do przechowywania metadanych metody meta.
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>();
}
}
Metoda statyczna montaż Sposób wywołania ekspresji lambda i następnie zwraca go jako pełnomocnika działania wykonywanego wcześniej (przekazany jako argument Invoke()
w swoim przypadku).
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();
}
Dziękujemy das .. więc za pomocą dostarczonego kodu - z ewentualnego „makeRed” obiekt Action być przechowywane w „chainedArgs” i wykonywane podczas „Invoke()” podczas rozmowy pętla łączenia? – mmacneil007
@ mmacneil007 Absolutnie, to jest idea. 'Działanie' jest delegatem, który może być przechowywany w jednej z tablic wewnątrz tablicy tablic 'chainedArgs' i przekazywany do odpowiedniej metody (w twoim przypadku byłaby to" OtherProperties "). –
dasblinkenlight
Doskonale, wierzę, że to postawiło mnie na właściwej drodze. Wciąż owijając głowę wokół drzewek ekspresji, ale myślę, że podejście, które tu przedstawiłeś, powinno załatwić sprawę. Dzięki jeszcze raz! – mmacneil007