Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Reflection with recursion

I am working on the Reflection , but i am stuck while doing the 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 the 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 whether the property is a class or the primitive. and do the recursion if it is a class.

like image 247
Syed Abdul Qadeer Avatar asked Feb 04 '13 09:02

Syed Abdul Qadeer


2 Answers

First of all, if you want to access the properties of a type, ensure you are using a type which 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;}
}

Second, prp.GetType() will always return PropertyInfo. You are looking for prp.PropertyType, which will return the Type of the property.

Also, if(!prp.GetType().IsPrimitive && prp.GetType().IsClass) won't work the way you want, because String e.g. is a class and also not a primitive. Better use prp.PropertyType.Module.ScopeName != "CommonLanguageRuntimeLibrary".

Last but not least, to use recursion, you actually have to put your code into a method.

Here's 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 like this:

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);

it will output

User.Name: Foo
User.Number: 19
User.Address.Street: MyStreet
User.Address.State: MyState
User.Address.Country: SomeCountry
like image 140
sloth Avatar answered Oct 12 '22 07:10

sloth


First of all, avoid using reflection unless you really need it. It's slow, it's messy, it's borderline undebuggable (and I love it, but that's another thing)

If you want to dump the whole content of your object, I would recommend to transfer that to the objects themselves, they should know their inner state. You could use the objects ToString method to write their inner state, or you could define an interface for displaying the inner state

interface IStateDisplay
{
   string GetInnerState();
}

and make your objects implement it. Then the code for displaying the properties will be

Console.WriteLine(user.GetInnerState());

Another option would be to use a tool like AutoMapper that hides the complexities and intricacies of reflection from you, and exposes a nice API to use.

However, if you are learning about reflection, printing the state of a complex object is a nice exercise. A few pointers in that direction:

public string Name;

is not a property, it's a field, so type.GetProperties() will not return it. Read up on what C# properties are, and how they are used and defined. A minimal property declaration is

public string Name {get; set;}

Also, prp.GetType() will return the type information for the PropertyInfo type, not for the type of the property it contains. What you need in this case is the prp.PropertyType property.

Next, I don't think the Type.IsPrimitive check is what you want it to be. That property returns true for the Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double, and Single types, and false for everything else. Most importantly typeof(string).IsPrimitive returns false.

On the same note, I don't think the Type.IsClass check is what you want it to be, either. As you are using it, that only check if the property is of a value or of a reference type, and as value types (struct) can be also very complex and contain properties and fields of their own, the check does not make sense.

like image 28
SWeko Avatar answered Oct 12 '22 07:10

SWeko