22

I am trying to set a value to a Nested Property of Class dynamically using reflection. Could anyone help me to do this.

I am having a class Region like below.

public class Region
{
    public int id;
    public string name;
    public Country CountryInfo;
}

public class Country
{
    public int id;
    public string name;
}

I have a Oracle Data reader to provide the Values from the Ref cursor.

which will give me as

Id,name,Country_id,Country_name

I could able to assign the values to the Region.Id, Region.Name by below.

FieldName="id"
prop = objItem.GetType().GetProperty(FieldName, BindingFlags.Public | BindingFlags.Instance);
prop.SetValue(objItem, Utility.ToLong(reader_new[ResultName]), null);

And for the Nested Property I could able to do the assign values to the as below by creating a Instance by reading the Fieldname.

FieldName="CountryInfo.id"

if (FieldName.Contains('.'))
{
    Object NestedObject = objItem.GetType().GetProperty(Utility.Trim(FieldName.Split('.')[0]), BindingFlags.Public | BindingFlags.Instance);

    //getting the Type of NestedObject
    Type NestedObjectType = NestedObject.GetType();

    //Creating Instance
    Object Nested = Activator.CreateInstance(typeNew);

    //Getting the nested Property
    PropertyInfo nestedpropinfo = objItem.GetType().GetProperty(Utility.Trim(FieldName.Split('.')[0]), BindingFlags.Public | BindingFlags.Instance);

    PropertyInfo[] nestedpropertyInfoArray = nestedpropinfo.PropertyType.GetProperties();
    prop = nestedpropertyInfoArray.Where(p => p.Name == Utility.Trim(FieldName.Split('.')[1])).SingleOrDefault();

    prop.SetValue(Nested, Utility.ToLong(reader_new[ResultName]), null);
    Nestedprop = objItem.GetType().GetProperty(Utility.Trim(FieldName.Split('.')[0]), BindingFlags.Public | BindingFlags.Instance);

    Nestedprop.SetValue(objItem, Nested, null);
}

The above assign values to Country.Id.

But Since I am creating instance each and every time I could not able to get the previous Country.Id value if I go for the Next Country.Name.

Could anybody tell could to assign values to the objItem(that is Region).Country.Id and objItem.Country.Name. Which means how to assign values to the Nested Properties instead of creating instance and assigning everytime.

Thanks in advance.!

2

4 Answers 4

65

You should be calling PropertyInfo.GetValue using the Country property to get the country, then PropertyInfo.SetValue using the Id property to set the ID on the country.

So something like this:

public void SetProperty(string compoundProperty, object target, object value)
{
    string[] bits = compoundProperty.Split('.');
    for (int i = 0; i < bits.Length - 1; i++)
    {
        PropertyInfo propertyToGet = target.GetType().GetProperty(bits[i]);
        target = propertyToGet.GetValue(target, null);
    }
    PropertyInfo propertyToSet = target.GetType().GetProperty(bits.Last());
    propertyToSet.SetValue(target, value, null);
}
Sign up to request clarification or add additional context in comments.

4 Comments

Why is this accepted as answer, it throws a nullref because GetValue() is returning null if the target is not instantiated yet, which will lead to an exception one line further.
Because this is not tutorial. This answer is short and sweet and contains only necessary code. It is your responsibility to add checks / exception handling based on your own requirements. The code works just fine btw.
If you want to check and instantiate the target if it is null, you can have the full sample code here: stackoverflow.com/questions/51934180/…
That's in vb.net @CodePope — but was close enough to help me out.
3

Get Nest properties e.g., Developer.Project.Name

private static System.Reflection.PropertyInfo GetProperty(object t, string PropertName)
            {
                if (t.GetType().GetProperties().Count(p => p.Name == PropertName.Split('.')[0]) == 0)
                    throw new ArgumentNullException(string.Format("Property {0}, is not exists in object {1}", PropertName, t.ToString()));
                if (PropertName.Split('.').Length == 1)
                    return t.GetType().GetProperty(PropertName);
                else
                    return GetProperty(t.GetType().GetProperty(PropertName.Split('.')[0]).GetValue(t, null), PropertName.Split('.')[1]);
            }

1 Comment

This solution has a major flaw, it will not work with generic Lists. For example you provide FirstObject.MyList[0].MyValue will simply crash because it ignores the [0] first instance
1

Expanding on Jon Skeets answer, if the value you're getting is null and you want to create an object for that type:

public void SetProperty(string compoundProperty, object target, object value)
{
  var bits = compoundProperty.Split('.');
  for (var i = 0; i < bits.Length - 1; i++) {
    var propertyToGet = target.GetType().GetProperty(bits[i]);
    var propertyValue = propertyToGet.GetValue(target, null);
    if (propertyValue == null) {
      propertyValue = Activator.CreateInstance(propertyToGet.PropertyType);
      propertyToGet.SetValue(target, propertyValue);
    }
    target = propertyToGet.GetValue(target, null);
  }
  var propertyToSet = target.GetType().GetProperty(bits.Last());
  propertyToSet.SetValue(target, value, null);
}

Comments

0

Expanding on Luke Garrigan Answer:

If you want to have it working also with non lists too:

public void SetProperty(string compoundProperty, object target, object value)
{
  var bits = compoundProperty.Split('.');
  if(bits == null) bits = new string[1]{compoundProperty};
  for (var i = 0; i < bits.Length - 1; i++) {
    var propertyToGet = target.GetType().GetProperty(bits[i]);
    var propertyValue = propertyToGet.GetValue(target, null);
    if (propertyValue == null) {
      propertyValue = Activator.CreateInstance(propertyToGet.PropertyType);
      propertyToGet.SetValue(target, propertyValue);
    }
    target = propertyToGet.GetValue(target, null);
  }
  var propertyToSet = target.GetType().GetProperty(bits.Last());
  propertyToSet.SetValue(target, value, null);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.