Using Reflection in C# to Get Properties of a Nested Object

Using reflection in C# to get properties of a nested object

I use following method to get the values from (nested classes) properties like

"Property"

"Address.Street"

"Address.Country.Name"

    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
{
var prop = src.GetType().GetProperty(propName);
return prop != null ? prop.GetValue(src, null) : null;
}
}

Here is the Fiddle: https://dotnetfiddle.net/PvKRH0

Getting Nested Object Property Value Using Reflection

var address = GetPropertyValue(GetPropertyValue(emp1, "Address"), "AddressLine1");

Object Employee doesn't have a single property named "Address.AddressLine1", it has a property named "Address", which itself has a property named "AddressLine1".

Get nested property values through reflection C#

When passing an object instance to the GetValue method, you need to pass the instance of the correct type:

// 1st level properties
var parentProperties = obj.GetType().GetProperties();
foreach (var prop in parentProperties)
{
// get the actual instance of this property
var propertyInstance = prop.GetValue(obj, null);

// get 2nd level properties
var mainObjectsProperties = prop.PropertyType.GetProperties();

foreach (var property in mainObjectsProperties)
{
// get the actual instance of this 2nd level property
var leafInstance = property.GetValue(propertyInstance, null);

// 3rd level props
var leafProperties = property.PropertyType.GetProperties();

foreach (var leafProperty in leafProperties)
{
Console.WriteLine("{0}={1}",
leafProperty.Name, leafProperty.GetValue(leafInstance, null));
}
}
}

You might do this recursively to simplify (generalize) the whole thing:

static void DumpObjectTree(object propValue, int level = 0)
{
if (propValue == null)
return;

var childProps = propValue.GetType().GetProperties();
foreach (var prop in childProps)
{
var name = prop.Name;
var value = prop.GetValue(propValue, null);

// add some left padding to make it look like a tree
Console.WriteLine("".PadLeft(level * 4, ' ') + "{0}={1}", name, value);

// call again for the child property
DumpObjectTree(value, level + 1);
}
}

// usage: DumpObjectTree(obj);

Set property in nested object using reflection

Type.GetGenericArguments() doesn't do anything like what I think you're assuming.

What you want here is recursion. Given ”Foo.Bar[1].Baz”, get Foo. Get Bar[1] from that. Get the PropertyInfo from Baz from its parent, use that to set the value of the Baz property of the Bar[1] property of Foo.

To break it down:

  1. Write a method that "cracks" a property name and uses out parameters to return both the name part and the index value part: "IndexedProperty[1]" goes in; "IndexedProperty" and integer 1 come out. "FooBar" goes in, "FooBar" and null come out. It returns true if there's an indexer, false if not.

    bool CrackPropertyName(string name, out string namePart, out object indexPart)
  2. Write a method that takes an object, and a string "PropertyName" or "IndexedPropety[0]" (not a path -- no dot) and returns the value of that property on that object. It uses CrackPropertyName() to simplify its job.

    object GetPropertyValue(object obj, string name)
  3. Write a method that sets a property value by name (not by path, just by name). Again, it uses CrackPropertyName() to simplify its job.

    void SetPropertyValue(object obj, string name, object newValue)
  4. A recursive method using the above:

    void SetPropertyValueByPath(object obj, string path, object newvalue)
    {
    var pathSegments = /* split path on '.' */;

    if (pathSegments.Length == 1)
    {
    SetPropertyValue(obj, pathSegments[0], newValue);
    }
    else
    {
    // If more than one remaining segment, recurse

    var child = GetNamedPropertyvalue(obj, pathSegments[0]);

    return SetPropertyValueByPath(obj, String.Join(".", pathSegments.Skip(1)), newValue);
    }
    }

These methods are all pretty trivial. Since you're using reflection anyway, you may as well go whole hog and write one non-generic method that sets any property of anything.

How to print all nested object properties name

I think reflection is the tool of choice for this problem. With reflection it is possible to examine every little detail of an object. The difficulty is rather examining the right details of an object that lead to the desired goal. And to find the right functionality for it.
The basis for the following example is the source code from your question.

NOTE: The following example is really not in good programming style, it is simply intended to show an approach to inspecting objects with reflection.

First I provided the corresponding classes with constructors so that the dependencies for the entire object are created.

public class Student
{
public Student()
{
var subject1 = new Subject();
List<Subject> Subjects = new List<Subject>();
Subjects.Add(subject1);
}

public int Id { get; set; }
public List<Subject> Subjects { get; set; }
}

public class Subject
{
public Subject()
{
ScoreCalculator = new ScoreCalculator();
}

public string Code { get; set; }
public ScoreCalculator ScoreCalculator { get; set; }
}

public class ScoreCalculator
{
public double Score { get; set; }
public bool Pass { get; set; }
}

Next, the object is created and passed to the method.

public static void Main()
{
var student = new Student();
PrintAllPropertiesNames(student);
}

The method shows only a fraction of the possibilities that are available. But it shows an approach how you could examine your objects.

public static void PrintAllPropertiesNames<T>(T obj)
{
if(obj == null) throw new ArgumentNullException(nameof(obj));

var objType = obj.GetType();
Console.WriteLine($"{objType.Name} Properties:");

var objProperties = objType.GetProperties();
foreach(var property in objProperties)
{
Console.WriteLine($" + {property.Name}");
}

var propertySubjects = objType.GetProperty("Subjects");
Console.WriteLine();
Console.WriteLine($"{propertySubjects.Name} Info:");
Console.WriteLine($" + Type: {propertySubjects.PropertyType}");

var subjectsArguments = propertySubjects.PropertyType.GetGenericArguments();
foreach(var argument in subjectsArguments)
{
Console.WriteLine($" + Generic Argument: {argument.Name}");
}
Console.WriteLine();

var subjectType = subjectsArguments[0];
var subjectProperties = subjectType.GetProperties();
Console.WriteLine($"{subjectType.Name} Properties:");
foreach(var property in subjectProperties)
{
Console.WriteLine($" + {property.Name}");
}
Console.WriteLine();

var scoreCalculater = subjectType.GetProperty("ScoreCalculator");
Console.WriteLine($"{scoreCalculater.Name} Properties:");
var scoreCalculatorProperties = scoreCalculater.PropertyType.GetProperties();
foreach(var property in scoreCalculatorProperties)
{
Console.WriteLine($" + {property.Name}");
}
}

The example produces the following output.

Student Properties:
+ Id
+ Subjects

Subjects Info:
+ Type: System.Collections.Generic.List`1[HelloWold.Subject]
+ Generic Argument: Subject

Subject Properties:
+ Code
+ ScoreCalculator

ScoreCalculator Properties:
+ Score
+ Pass

I can recommend the MSDN to go deeper into the topic:
Reflection inC#

I hope I could help you with this.

C# Reflection get object for GetValues in nested Property Type

Your problem really boils down to the fact that you need to obtain an instance of the immediate property from which to extract the value of the nested property.

In concrete words - you need to obtain the value (instance) of the immediate property "inobjects" before you can resolve the value of the nested property propertyName.

Ideally you will cache the PropertyInfo instance but to make the code work in the simplest way possible - resolve the value like this:

...
if (pi.Name == PropertyName)
{
var value =
myObject.GetType()
.GetProperty("inobjects")
.GetValue(myObject, null);

s = (string) pi.GetValue(value, null);
}

You might be interested to know that you do not need to manually iterate over each property and that you could use GetProperty instead (which will return null if the property does not exist). I took the liberty of refactoring your code for you:

public static string GetNestedProperty(object value, string propertyName)
{
var type = value.GetType();
var property = type.GetProperty("inobjects");
value = property.GetValue(value, null);
type = property.PropertyType;

property = type.GetProperty(propertyName);

if (property == null)
{
return null;
}

value = property.GetValue(value, null);
return (string) value;
}

C# Reflection: getting a nested objects properties

By doing type.GetType() you are getting typeof(Type), not the property type.

Just do

PropertyInfo[] props = type.GetProperties();

to get the properties which you want.

However, you should look up properties by their name and not by their order, because the order is not guaranteed to be as you expect it (see documentation):

The GetProperties method does not
return properties in a particular
order, such as alphabetical or
declaration order. Your code must not
depend on the order in which
properties are returned, because that
order varies.

Get Property Value from Nested Objects - Efficient Ways than Reflection

You can use expression trees to create an abstract syntax tree that you can then compile to a dynamic method. This performs very closely to regularly written code (from my testing it is many times faster then reflection). The creation of the dynamic method is expensive, so create once, use many times.

static Func<object,object> CreateDelegate(PropertyInfo[] path)
{
var rootType = path.First().DeclaringType;
var param = Expression.Parameter(typeof(object));
Expression access = Expression.Convert(param, rootType);
foreach (var prop in path)
{
access = Expression.MakeMemberAccess(access, prop);
}

var lambda = Expression.Lambda<Func<object, object>>(
Expression.Convert(access, typeof(object)),
param
).Compile();

return lambda;
}

static void Main(string[] args)
{
var path = new[]
{
typeof(Root).GetProperty("Level1"),
typeof(Level1).GetProperty("Level2"),
typeof(Level2).GetProperty("Name")
};

var method = CreateDelegate(path);
var data = new Root { Level1 = new Level1 { Level2 = new Level2 { Name = "Test" } } };
var result = method(data);
}

References: Dynamic Methods, Expression Tree-Compile



Related Topics



Leave a reply



Submit