2

I have the following object:

public class ContactImport { 
    public long Id {get;set;}
    public Contact Contact {get;set;}
    public Company Company {get;set;}
    public Address Address {get;set;}
}

I want to be able to set the properties on the the nested objects dynamically based on an expression passed in (Expression<Func<T, dynamic>>).

To do this I have the following method, this works fine for setting properties on the top level object (such as Id) but fails when trying to set anything on the nested objects (such as Contact.FirstName)

public static void SetPropertyValue<T, TProp>(this T target, Expression<Func<T, TProp>> member, TProp value) {
    var selectorExpr = (MemberExpression)(member.Body is UnaryExpression ? ((UnaryExpression)member.Body).Operand : member.Body);
    if (selectorExpr != null) {
        var property = selectorExpr.Member as PropertyInfo;
        if (property != null) {
            property.SetValue(target, value);
        }
     }
 }

It looks like it's trying to set the property on the top level object but can't. I take it this is possible but I'm unsure how to achieve it with what I currently have.

The SetPropertyValue method is invoke like this:

public class ImportCheck<T> {

    public int id { get; set; }
    public string Name { get; set; }
    public Type Type { get; set; }
    public bool Required { get; set; }
    public int? MinLength { get; set; }
    public int? MaxLength { get; set; }
    public string Value { get; set; }
    public Expression<Func<T, dynamic>> AssociatedProperty { get; set; }
}


    T pt = (T)Activator.CreateInstance(typeof(T));
    foreach (var m in mapping) {
        pt.SetPropertyValue(m.AssociatedProperty, Convert.ChangeType(m.Value, Nullable.GetUnderlyingType(m.Type) ?? m.Type));
    }

In the above example T is ContactImport, m.AssociatedProperty is the expression and mapping is a List<ImportCheck<ContactImport>>.

Update

My issue seems to boil down to the fact that the expression being passed into SetPropertyValue has a return type of dynamic. If this is set to int and the property on the nested object is an int then it all works. The problem I have then is that I need to explicitly set the result of the expression to match the type of the target property. This however leaves me with another issue in that I need a list of ImportChecks with the possibility of each Expression<Func<T,dynamic>> having a different return type.

Gaz
  • 1,249
  • 3
  • 19
  • 37
  • 1
    Please show a sample invocation of `SetPropertyValue`. – Sergey Kalinichenko Jul 08 '15 at 21:02
  • 1
    Why you don't use SetPropertyValue ,directly? like: `ContactImport.Address.SetPropertyValue(c => c.id, 5)' ? – Ali Adlavaran Jul 08 '15 at 21:06
  • I have taken a string before to build a property expression, https://github.com/tbd-develop/roastpotato/blob/master/server/dotnet/RoastPotato.Recipes/Infrastructure/RecipeExtensions.cs it wouldn't be too hard to adapt this to give you an expression to set. – tbddeveloper Jul 08 '15 at 21:16
  • 1
    "Nested properties" generally implies recursion. If you can provide [a good, _minimal_, _complete_ code example](https://stackoverflow.com/help/mcve) that clearly illustrates your question, it would be feasible to provide an actual answer. In the meantime, [my answer to this previous question](https://stackoverflow.com/a/30333434) might give you some ideas about how to proceed. (It uses reflection instead of expressions and is specifically about value types, but the basic concepts are the same). – Peter Duniho Jul 08 '15 at 21:31
  • @AliAdlavaran I can't do that as it's a generic method which is why I use the expression, this way I can use the same function for multiple different import types. – Gaz Jul 08 '15 at 21:54
  • @dasblinkenlight Hope the above edit helps the `AssociatedProperty` would be set using something like `x=>x.Contact.FirstName` – Gaz Jul 08 '15 at 21:58

0 Answers0