0

What I'm trying to achieve is to create Action to assign a value to the object property defined by a string. What i have come up with so far is:

void Main()
{
    var startPropertyName= "StartTime";
    var endPropertyName= "EndTime";


    var myAction = AssignValueToProperty<MyClass>(startPropertyName, DateTime.Today);

    var myObject = new MyClass();
    myAction(myObject);
    myObject.StartTime.Dump();

}

public static Action<T> AssignValueToProperty<T>(string propertyName, DateTime value)
{
    var arg = Expression.Parameter(typeof(T));
    var property = Expression.Property(arg, propertyName);

    var cons = Expression.Constant(value, typeof(DateTime));

    var body = Expression.Assign(property, cons);
    var exp = Expression.Lambda<Action<T>>(body, new ParameterExpression[] { arg });
    return exp.Compile();
}

public class MyClass
{
    public DateTime StartTime { get; set; }
    public DateTime EndTime { get; set; }
}

But i would like to pass the DateTime parameter during calling the Action not during creating it. And possibly add another parameter for EndTime Property.

canton7
  • 37,633
  • 3
  • 64
  • 77
mdziadowiec
  • 396
  • 3
  • 10
  • Which part of your problem are you struggling with? You just want to add another parameter to the lambda, so why not do that? – canton7 Jan 13 '20 at 10:57
  • I want to create an Action like this `AssignValueToProperty(startPropertyName)` and call it like this: `myAction(myObject,DateTime.Now);` – mdziadowiec Jan 13 '20 at 10:59

1 Answers1

2

You were most of the way there. Just declare another ParameterExpression for your new parameter.

public static Action<T, DateTime> AssignValueToProperty<T>(string propertyName)
{
    var arg = Expression.Parameter(typeof(T), "arg");
    var startTime = Expression.Parameter(typeof(DateTime), "startTime");
    var property = Expression.Property(arg, propertyName);

    var body = Expression.Assign(property, startTime);
    var exp = Expression.Lambda<Action<T, DateTime>>(body, new ParameterExpression[] { arg, startTime });
    return exp.Compile();
}

canton7
  • 37,633
  • 3
  • 64
  • 77
  • It works, you just missed quotation marks in `var startTime = Expression.Parameter(typeof(DateTime), "startTime");` and actualy asign the starttime i the Assign method `var body = Expression.Assign(property, startTime);` – mdziadowiec Jan 13 '20 at 11:09
  • Oops, knocked that out on the way to a meeting. Fixed! – canton7 Jan 13 '20 at 11:21
  • I think the names of the paramters aren't even necessary right? – mdziadowiec Jan 13 '20 at 11:24
  • 1
    They're not, but it helps a lot when debugging. If you look at the `DebugView` property of an expression in the debugger, it uses the names in the generated pseudo-code it shows you. – canton7 Jan 13 '20 at 11:30
  • is there a way to infer type of T dynamically so i could call `var myAction = AssignValueToProperty(startPropertyName, DateTime.Today);` instead of `var myAction = AssignValueToProperty(startPropertyName, DateTime.Today);` because i know the type only during runtime. I was looking at this example [link](https://stackoverflow.com/a/25812889/2458980) but the "Using Expresion Tree" part actually Converts the parameter to the type provided by the user input – mdziadowiec Jan 13 '20 at 14:10
  • At the point that you compile the expression, you need to know the type of the object you're setting the property on. You don't necessarily need to know it as a `T` (it could be a `Type` object), but it does need to be known – canton7 Jan 13 '20 at 14:16