Można oczywiście przejść drzewo ekspresji, a następnie użyć Delegate.CreateDelegate
, aby utworzyć odpowiednie Action<,>
. Jest to dość proste, z wyjątkiem wszystkich walidacji kontrole (jestem pewien, czy mam wszystko pokryte):
nie jestem ekspertem wyrażenie drzewa, ale nie myśleć budowania wypowiedzi -tree, a następnie wywołanie Compile
jest możliwe tutaj, ponieważ drzewa-wyrażenia nie mogą zawierać instrukcji przypisania, o ile wiem. (EDIT: Najwyraźniej zostały one dodane w .NET 4. Jest to trudna do znalezienia funkcja, ponieważ kompilator C# nie wydaje się być w stanie zbudować ich z lambdas).
public static Action<TContaining, TProperty>
CreateSetter<TContaining, TProperty>
(Expression<Func<TContaining, TProperty>> getter)
{
if (getter == null)
throw new ArgumentNullException("getter");
var memberEx = getter.Body as MemberExpression;
if (memberEx == null)
throw new ArgumentException("Body is not a member-expression.");
var property = memberEx.Member as PropertyInfo;
if (property == null)
throw new ArgumentException("Member is not a property.");
if(!property.CanWrite)
throw new ArgumentException("Property is not writable.");
return (Action<TContaining, TProperty>)
Delegate.CreateDelegate(typeof(Action<TContaining, TProperty>),
property.GetSetMethod());
}
Wykorzystanie:
public class Person { public int Age { get; set; } }
...
static void Main(string[] args)
{
var setter = CreateSetter((Person p) => p.Age);
var person = new Person();
setter(person, 25);
Console.WriteLine(person.Age); // 25
}
Należy pamiętać, że to tworzy otwarty instancji delegata, co oznacza, że nie jest związana z żadnym konkretnym wystąpieniem TContaining
. Można go łatwo zmodyfikować, aby był związany z instancją specyficzną dla instancji; musisz również podać metodę TContaining
, a następnie użyć innego przeciążenia: Delegate.CreateDelegate
. Podpis metody będzie wtedy wyglądać tak:
public static Action<TProperty> CreateSetter<TContaining, TProperty>
(Expression<Func<TContaining, TProperty>> getter, TContaining obj)
Nie masz na myśli "Akcji"? Moglibyśmy również wprowadzić parametr "int" jako typ. –
Ani
Ani, tak masz rację - miałem na myśli Action i int będzie oczywiście również parametrem generycznym. –
Alex