C # Reflection with recursion

I am working on Reflection, but I am stuck when doing recursion.

Code:

public class User { public string Name; public int Number; public Address Address; } public class Address { public string Street; public string State; public string Country; } 

now i am printing values.

  Type t = user.GetType(); PropertyInfo[] props = t.GetProperties(); foreach (PropertyInfo prp in props) { if(!prp.GetType().IsPrimitive && prp.GetType().IsClass) { // Get the values of the Inner Class. // i am stucked over here , can anyone help me with this. Type ty = prp.GetType(); var prpI = ty.GetProperties(); //var tp = ty.GetType().; foreach (var propertyInfo in prpI) { var value = propertyInfo.GetValue(prp); var stringValue = (value != null) ? value.ToString() : ""; console.WriteLine(prp.GetType().Name + "." + propertyInfo.Name+" Value : " +stringValue); } } else { var value = prp.GetValue(user); var stringValue = (value != null) ? value.ToString() : ""; console.writeline(user.GetType().Name + "." + prp.Name+" Value : " +stringValue); } } 

I want to know how to find out if a property is a class or primitive. and do recursion if it is a class.

+4
source share
5 answers

First of all, if you want to access the properties of a type, make sure you use a type that has properties:

 public class User { public string Name{get;set;} public int Number{get;set;} public Address Address{get;set;} } public class Address { public string Street{get;set;} public string State{get;set;} public string Country{get;set;} } 

Secondly, prp.GetType() will always return PropertyInfo . You are looking for prp.PropertyType that will return a property type.

Also, if(!prp.GetType().IsPrimitive && prp.GetType().IsClass) will not work the way you want, because String for example. is a class, and also not primitive. It is better to use prp.PropertyType.Module.ScopeName != "CommonLanguageRuntimeLibrary" .

Last but not least, to use recursion, you really need to put your code in a method.

Here is a complete example:

 IEnumerable<string> GetPropertInfos(object o, string parent=null) { Type t = o.GetType(); PropertyInfo[] props = t.GetProperties(BindingFlags.Public|BindingFlags.Instance); foreach (PropertyInfo prp in props) { if(prp.PropertyType.Module.ScopeName != "CommonLanguageRuntimeLibrary") { // fix me: you have to pass parent + "." + t.Name instead of t.Name if parent != null foreach(var info in GetPropertInfos(prp.GetValue(o), t.Name)) yield return info; } else { var value = prp.GetValue(o); var stringValue = (value != null) ? value.ToString() : ""; var info = t.Name + "." + prp.Name + ": " + stringValue; if (String.IsNullOrWhiteSpace(parent)) yield return info; else yield return parent + "." + info; } } } 

Used as follows:

 var user = new User { Name = "Foo", Number = 19, Address = new Address{ Street="MyStreet", State="MyState", Country="SomeCountry" } }; foreach(var info in GetPropertInfos(user)) Console.WriteLine(info); 

he will output

 User.Name: Foo User.Number: 19 User.Address.Street: MyStreet User.Address.State: MyState User.Address.Country: SomeCountry 
+12
source

First of all, avoid using reflection unless you really need it. He is slow, he is dirty, he is borderline undebuggable (and I love him, but it's different)

If you want to dump all the content of your object, I would recommend passing it to the objects themselves, they should know their internal state. You can use the ToString method to record your internal state, or you can define an interface to display internal state

 interface IStateDisplay { string GetInnerState(); } 

and your objects implement it. Then the code to display the properties will be

 Console.WriteLine(user.GetInnerState()); 

Another option would be to use a tool like AutoMapper , which hides the complexities and subtleties of reflection from you and provides a good API to use.

However, if you are studying reflection, printing the state of a complex object is a good exercise. A few pointers in this direction:

 public string Name; 

is not a property, this is a field, so type.GetProperties() will not return it. Read what C # properties are and how they are used and defined. Declaring a Minimum Property

 public string Name {get; set;} 

In addition, prp.GetType() will return type information for the PropertyInfo type, and not for the type of the property it contains. In this case, you will need the prp.PropertyType property.

Further, I do not think Type.IsPrimitive is what you want. This property returns true for Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double and Single and false for everything else. Most importantly, typeof(string).IsPrimitive returns false.

In the same note, I do not think that checking Type.IsClass is what you want. Since you use it, it only checks if the property has a value or a reference type, and also how the value types ( struct ) can also be very complex and contain their own properties and fields, the check does not make sense.

+2
source
  using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; namespace Extensions { public static class ObjectExtension { public static string ToStringProperties(this object o) { return o.ToStringProperties(0); } public static string ToStringProperties(this object o, int level) { StringBuilder sb = new StringBuilder(); string spacer = new String(' ', 2 * level); if (level == 0) sb.Append(o.ToString()); sb.Append(spacer); sb.Append("{\r\n"); foreach (PropertyInfo pi in o.GetType().GetProperties()) { if (pi.GetIndexParameters().Length == 0) { sb.Append(spacer); sb.Append(" "); sb.Append(pi.Name); sb.Append(" = "); object propValue = pi.GetValue(o, null); if (propValue == null) { sb.Append(" <null>"); } else { if (IsMyOwnType(pi.PropertyType)) { sb.Append("\r\n"); sb.Append(((object)propValue).ToStringProperties(level + 1)); } else{ sb.Append(propValue.ToString()); } } sb.Append("\r\n"); } } sb.Append(spacer); sb.Append("}\r\n"); return sb.ToString(); } private static bool IsMyOwnType(Type t) { return (t.Assembly == Assembly.GetExecutingAssembly()); } } } 
0
source

Thanks to @Sloth, the code is very useful. This is a small modification of those who receive a "link to an object not installed on an instance of the object." error. It creates an instance of the null object and also processes arrays. More needs to be done to handle all possible types of collections, but this is the beginning.

 public static IEnumerable<string> GetPropertInfos(object o, string parent = null) { Type t = o.GetType(); // String namespaceValue = t.Namespace; PropertyInfo[] props = t.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (PropertyInfo prp in props) { if (prp.PropertyType.Module.ScopeName != "CommonLanguageRuntimeLibrary") { // fix me: you have to pass parent + "." + t.Name instead of t.Name if parent != null object value = prp.GetValue(o); if (value == null) { value = Activator.CreateInstance(Type.GetType( (prp.PropertyType).AssemblyQualifiedName.Replace("[]", ""))); } var propertInfos = GetPropertInfos(value, t.Name); foreach (var info in propertInfos) yield return info; } else { var type = GetTypeName(prp); var info = t.Name + "." + prp.Name ; if (String.IsNullOrWhiteSpace(parent)) yield return info; else yield return parent + "." + info; } } } 
0
source

You can use the Type.IsValueType property.

-1
source

All Articles