-3

I'm trying to clean up my class using reflection.

private List<String> centers = new List<String>();
private List<String> leftWingers = new List<String>();
private List<String> rightWingers = new List<String>();
private List<String> defencemen = new List<String>();
private List<String> goalies = new List<String>();
private List<String> bench = new List<String>();

public List<String> Centers { get { return centers; } set { centers = value; } }
public List<String> LeftWingers { get { return leftWingers; } set { leftWingers = value; } }
public List<String> RightWingers { get { return rightWingers; } set { rightWingers = value; } }
public List<String> Defencemen { get { return defencemen; } set { defencemen = value; } }
public List<String> Goalies { get { return goalies; } set { goalies = value; } }
public List<String> Bench { get { return bench; } set { bench = value; } }

public String ToString()
{
    String output = "";

    System.Reflection.PropertyInfo[] properties = this.GetType().GetProperties();

    foreach (System.Reflection.PropertyInfo property in properties)
    {
        int count = 0;
        foreach (String value in property)
        {
            count++;
            output += "C" + count + ": " + value + System.Environment.NewLine;
        }

    }
}

This will not work. I cant seem to be able to loop over items of each property because they are collections. Is there a way to get the contents of the String Lists from the PropertyInfo object?

Slack Groverglow
  • 846
  • 7
  • 25
  • Those are fields, not properties - something like `this.GetType().GetFields().Select(f => f.GetValue(this))`? – Orphid Feb 24 '16 at 22:48
  • 3
    Are they six collections only? Why do you want to use reflection? – Yacoub Massad Feb 24 '16 at 22:49
  • use GetFields() instead – Arturo Menchaca Feb 24 '16 at 22:50
  • There are plenty of ways to improve that code... and reflection at best should be last on the list of things to try. I.e. just getting all arrays into collection would be enough to simplify code without reflection. – Alexei Levenkov Feb 24 '16 at 22:56
  • @AlexeiLevenkov This could be a simplified example. The call to this.GetType() allows for the retrieval of members defined on derived types too. Not a great approach of course, but this.GetType() will have an impact on derived types that clearing a collection of collections in the base class wont – Orphid Feb 24 '16 at 23:01
  • This answers may help if you really want to use reflection over all fields - http://stackoverflow.com/questions/1120839/net-c-reflection-list-the-fields-of-a-field-that-itself-has-fields... As well as discussion on LinqPad's Dump method (which maybe what your trying to clone) - http://stackoverflow.com/questions/2699466/linqpad-dump-extension-method-i-want-one – Alexei Levenkov Feb 24 '16 at 23:14

4 Answers4

3
  1. They are not properties, they are fields,so you need to use GetFields
  2. You need to tell GetFields method that you want to get private members using BindingFlags, otherwise it will look for public and instance members by default.

    var fields = this.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
    
Selman Genç
  • 100,147
  • 13
  • 119
  • 184
1

Well, if you really want properties, the first thing is that you do not have properties on your code. You have just some attributes. Change it for properties if it is the case, for sample:

private List<String> centers { get; set; }
private List<String> leftWingers { get; set; }
private List<String> rightWingers { get; set; }
private List<String> defencemen { get; set; }
private List<String> goalies { get; set; }
private List<String> bench { get; set; }

Then you could read them as collections and read values, for sample:

public String ToString()
{
    StringBuilder output = new StringBuilder();

    System.Reflection.PropertyInfo[] properties = this.GetType().GetProperties();

    foreach (System.Reflection.PropertyInfo property in properties)
    {
        var values = property.GetValue(this, null) as IEnumerable<String>;

        if (values != null) 
        {
            int count = 0;
            foreach (String value in values)
            {
                count++;
                output.AppendLine(string.Format("C{0}: {1}", count, value));
            }
        }
    }

    return output.ToString();
}

Another case is to read the fields and avoid converting it to properties. Look the Selman22's answer!

Felipe Oriani
  • 37,948
  • 19
  • 131
  • 194
1

Your problem can be drastically simplified using Enumerable.Concat, Enumerable.Select and string.Join:

IEnumerable<string> allItems = centers.Concat(leftWingers)
                                      .Concat(rightWingers)
                                      .Concat(defencemen)
                                      .Concat(goalies)
                                      .Concat(bench);

return string.Join
(
    Environment.NewLine, 
    allItems.Select((item, index) => $"C {index + 1}: {item}")
);
Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
0

These are fields, so you need to use GetFields to obtain them. Please note also that fields returned by reflection are just metadata, they don't contain the data that you need.

To get the data, you need to use the GetValue method to get the field value for the current object.

Then, to be able to enumerate the collection in the field, you need to cast it as IEnumerable<string>.

Here is how it would look like:

public String ToString()
{
    String output = "";

    var fields = this.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);

    foreach (var field in fields)
    {
        int count = 0;
        foreach (String value in (IEnumerable<string>) field.GetValue(this))
        {
            count++;
            output += "C" + count + ": " + value + System.Environment.NewLine;
        }
    }
    return output;
}    

Since you have only 6 collections, you can have a solution that does not involve reflection. Here is an example:

public String ToString()
{
    String output = "";

    var collections = new[] {centers, leftWingers, rightWingers, defencemen, goalies, bench};

    foreach (var field in collections)
    {
        int count = 0;
        foreach (String value in field)
        {
            count++;
            output += "C" + count + ": " + value + System.Environment.NewLine;
        }
    }
    return output;
}    

Please consider using a StringBuilder instead of a string. Using a string to concatenate strings will hurt performance.

Yacoub Massad
  • 27,509
  • 2
  • 36
  • 62