My question is very similar to the following two questions but I have an added requirement that these do not satisfy.
- How to set property value using Expressions?
- How set value a property selector Expression<Func<T,TResult>>
Just like those questions, I have an Expression<Func<TEntity, TProperty>>
where I want to set a value to the specified property. And those solutions work great if the body of the expression is only one level deep, such as x => x.FirstName
but they don't work at all if that body is deeper, like x => x.Parent.FirstName
.
Is there some way to take this deeper expression and set the value to it? I don't need a terribly robust execution-deferred solution but I do need something that I can execute on an object and it would work whether 1-level or multiple levels deep. I also need to support most typical types you'd expect in a database (long
, int?
, string
, Decimal
, DateTime?
, etc. although I don't care about more complex things like geo types).
For conversation's sake, let's say we're working with these objects although assume we need to handle N levels deep, not just 1 or 2:
public class Parent
{
public string FirstName { get; set; }
}
public class Child
{
public Child()
{
Mom = new Parent(); // so we don't have to worry about nulls
}
public string FavoriteToy { get; set; }
public Parent Mom { get; set; }
}
and let's say this is our unit test:
[TestFixture]
public class Tests
{
[Test]
public void MyTest()
{
var kid = new Child();
Expression<Func<Child, string>> momNameSelector = (ch => ch.Mom.FirstName);
Expression<Func<Child, string>> toyNameSelector = (ch => ch.FavoriteToy);
kid.ExecuteMagicSetter(momNameSelector, "Jane");
kid.ExecuteMagicSetter(toyNameSelector, "Bopp-It!");
Assert.That(kid.Mom.FirstName, Is.EqualTo("Jane"));
Assert.That(kid.FavoriteToy, Is.EqualTo("Bopp-It!"));
}
}
and our extension method we're looking at (I'm not set on it needing to be an extension method but it seems simple enough) would look like this:
public static TEntity ExecuteMagicSetter<TEntity, TProperty>(this TEntity obj, Expression<Func<TEntity, TProperty>> selector, TProperty value)
where TEntity : class, new() // I don't require this but I can allow this restriction if it helps
{
// magic
}
P.S. This version of code was written in the SO editor - my apologies for dumb syntax issues but this should be darn close! #LockedDownWorkstationsSuck