Por supuesto, puede caminar el árbol de expresiones y luego usar Delegate.CreateDelegate
para crear el Action<,>
apropiado. Es muy sencillo, excepto por todas las comprobaciones de validación-(no estoy seguro si he cubierto todo):
No soy un experto expresión de árboles, pero no lo hago pensar la construcción de una expresión -tree y luego llamar al Compile
es posible aquí ya que los árboles de expresión no pueden contener sentencias de asignación, hasta donde yo sé. (EDIT: Aparentemente, estos se han agregado en .NET 4. Es una característica difícil de encontrar ya que el compilador de C# no parece ser capaz de compilarlos a partir de 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());
}
Uso:
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
}
tenga en cuenta que esto crea un delegado ejemplo abierta, lo que significa que no está ligada a ninguna instancia particular de TContaining
. Es simple modificarlo para vincularlo a una instancia específica; También deberá pasar un TContaining
al método y luego usar una sobrecarga diferente de Delegate.CreateDelegate
. La firma del método sería entonces algo como:
public static Action<TProperty> CreateSetter<TContaining, TProperty>
(Expression<Func<TContaining, TProperty>> getter, TContaining obj)
¿No te refieres a 'Action'? Además, podríamos hacer 'int' un parámetro de tipo también. –
Ani
Ani, sí, tienes razón, me refería a la Acción y, por supuesto, int también será un parámetro genérico. –
Alex