Nick
Nick

Reputation: 533

C# Conversion of recursive iteration of properties' values for List<> property

I have the following method which I use to iterate through all properties (just properties) in my classes and print on screen their names and values they hold, if any.

        public static void PrintProperties(object obj, int indent = 1)
        {
        if ( obj == null )
            return;
        string indentString = new string (' ', indent);

        Type objType = obj.GetType ();
        PropertyInfo[] properties = objType.GetProperties ();

        foreach ( PropertyInfo property in properties )
        {
            object propValue = property.GetValue (obj, null);
            var elems = propValue as IList;
            if ( elems != null )
            {
                foreach ( var item in elems )
                {
                    PrintProperties (item, indent + 3);
                }
            }
            else
            {
                if ( property.PropertyType.Assembly == objType.Assembly )
                {
                    Console.WriteLine("{0}{1}:", indentString, property.Name);

                    PrintProperties (propValue, indent + 2);
                }
                else
                {
                    Console.WriteLine("{0}{1}: {2}", indentString, property.Name, propValue);
                }
            }
            }

Unfortunately, I change a property in one of my Classes from string to List<string> to accommodate for multiple values that I had to assign there, and now I get error System.Reflection.TargetParameterCountException: 'Parameter count mismatch.' which I don't know how to fix, and most probably is because I have a property that is List. How can i fix so that when I encounter such a property, to list all its values? Could someone help me please?

Upvotes: 0

Views: 888

Answers (2)

Jamiec
Jamiec

Reputation: 136239

The problem in this line where the error occurs:

object propValue = property.GetValue (obj, null);

Has nothing to do with the list per se. It is the recursive nature of your method trying to do enumerate all the properties on string. A simple solution, if you only want to print the values of the list is to change the part that enumerates the list as simply:

var elems = propValue as IList;
if ( elems != null )
{
     Console.WriteLine("{0}{1}:", indentString, property.Name);
     foreach ( var item in elems )
     {
            Console.WriteLine("{0}{1}",new string (' ', indent+2),item);
     }
}

https://dotnetfiddle.net/NBOA4u

Upvotes: 1

Matthew Watson
Matthew Watson

Reputation: 109862

You have to do three things to fix your implementation:

  1. Handle strings specially (because otherwise they will be treated as char arrays in your implementation).
  2. Handle arrays specially (otherwise you get the exception that you're seeing).
  3. Print out the value of each item, not just its properties. Otherwise, if that item is, say, an int then it won't get printed out.

Something along these lines should work:

public static void PrintProperties(object obj, int indent = 1)
{
    if (obj == null)
        return;

    string indentString = new string(' ', indent);

    Type objType    = obj.GetType();
    PropertyInfo[] properties = objType.GetProperties();

    foreach (PropertyInfo property in properties)
    {
        object propValue;

        if (objType == typeof(string))
            return; // Handled at a higher level, so nothing to do here.

        if (property.PropertyType.IsArray)
            propValue = (Array)property.GetValue(obj);
        else
            propValue = property.GetValue(obj, null);

        var elems = propValue as IList;

        if (elems != null)
        {
            Console.WriteLine("{0}{1}: IList of {2}", indentString, property.Name, propValue.GetType().Name);

            for (int i = 0; i < elems.Count; ++i)
            {
                Console.WriteLine("{0}{1}[{2}] == {3}", indentString, property.Name, i, elems[i]);

                if (objType != typeof(string))
                    PrintProperties(elems[i], indent + 3);
            }
        }
        else
        {
            if (property.PropertyType.Assembly == objType.Assembly)
            {
                Console.WriteLine("{0}{1}:", indentString, property.Name);

                PrintProperties(propValue, indent + 2);
            }
            else
            {
                Console.WriteLine("{0}{1}: {2}", indentString, property.Name, propValue);
            }
        }
    }
}

You will probably want to adjust the output to suit what you actually want, but this should give you the gist.

Upvotes: 1

Related Questions