2

Let's say we have a class Root that has BasicDetails class property and then basicDetails has two properties. A string "Name" and a dynamic object called "CustomAttributes".

I want to get the value in the following manner:

  var root = new Root();
  root.BasicDetails.Name = "Samurai";
  root.BasicDetails.CustomAttributes.phone = "12345";
  string res1 = GetDeepPropertyValue(root, "BasicDetails.CustomAttributes.Phone").ToString();
  string res2 = GetDeepPropertyValue(root, "BasicDetails.Name").ToString();

The following is the code I have tried (based on another answer on SO):

public static object GetDeepPropertyValue(object src, string propName)
{
    if (propName.Contains('.'))
    {
        string[] Split = propName.Split('.');
        string RemainingProperty = propName.Substring(propName.IndexOf('.') + 1);
        return GetDeepPropertyValue(src.GetType().GetProperty(Split[0]).GetValue(src, null), RemainingProperty);
    }
    else
        return src.GetType().GetProperty(propName).GetValue(src, null);
}

The following are the classes:

public class Root
{
    public Root()
    {
        BasicDetails = new BasicDetails();
    }
    public BasicDetails BasicDetails { get;set;}
}
public class BasicDetails
{
    public BasicDetails()
    {
        CustomAttributes = new ExpandoObject();
    }
    public string Name { get; set; }
    public dynamic CustomAttributes { get; set; }
}

The function that I have tried is throwing null reference error. Unfortunately I do not understand reflection too well so at the moment I am monkey patching. If someone could please explain c#how this can be done it would be great. Thank you in advance.

SamuraiJack
  • 5,131
  • 15
  • 89
  • 195
  • Hi there, where does ```ExpandoObject``` come from? Seems to be missing – Scircia Apr 06 '21 at 12:12
  • 2
    @Scircia It's a built-in class from `System.Dynamic` namespace – Pavel Anikhouski Apr 06 '21 at 12:21
  • Ah @PavelAnikhouski I see. My bad haha. – Scircia Apr 06 '21 at 12:34
  • @SamuraiJack, the issue is coming from ```src.GetType().GetProperty(propName).GetValue(src, null)``` due to ```GetProperty``` will return null on ```ExpandoObject``` and this will cause the NullReferenceException. Drik explains it quite nice in [his answer](https://stackoverflow.com/a/32312740/6809132). You need to change the logic for ```GetDeepPropertyValue``` and check if ```src.GetType().GetProperty(propName) ``` returns anything before calling ```GetValue``` If it doesn't get a value you'll need to create a check to determine what src is and based on that fetch its value – Scircia Apr 06 '21 at 12:59
  • @SamuraiJack, I have attached a working code example. For ExpandoObject, another solution needed. – Ugur Apr 06 '21 at 13:01

1 Answers1

1

Following method gets values from nested properties:

    public static object GetPropertyValue(object src, string propName)
    {
        if (src == null) throw new ArgumentException("Value cannot be null.", "src");
        if (propName == null) throw new ArgumentException("Value cannot be null.", "propName");

        if (propName.Contains("."))//complex type nested
        {
            var temp = propName.Split(new char[] { '.' }, 2);
            return GetPropertyValue(GetPropertyValue(src, temp[0]), temp[1]);
        }
        else
        {
            if (src is ExpandoObject)
            {
                var expando = src as IDictionary<string, object>;

                if (expando != null)
                {
                    object obj;
                    expando.TryGetValue(propName, out obj);
                    return obj;
                }

                return null;
            }
            else
            {
                var prop = src.GetType().GetProperty(propName);
                return prop != null ? prop.GetValue(src, null) : null;
            }
        }
    }

Usage:

 string res1 = GetPropertyValue(root, "BasicDetails.CustomAttributes.phone") as string;
 string res2 = GetPropertyValue(root, "BasicDetails.Name") as string;
Ugur
  • 1,257
  • 2
  • 20
  • 30
  • that works flawlessly! I understand that for expando object I need to deal with it differently but the solution was not working even when there was anther class object instead of ExpandoObject. I wonder why/ – SamuraiJack Apr 06 '21 at 13:39
  • you had also typo, property "phone" was written with lower case by setting and by getting it was upper case. – Ugur Apr 06 '21 at 13:44