1

Leveraging off the Q&As dealing with looping through an object's properties (https://stackoverflow.com/questions/15586123/loop-through-object-and-get-properties, Loop Through An Objects Properties In C#), where you have:

  • a collection of Class1 objects (i.e. listObj1)
  • each Class1 contains a collection of Class2 objects (i.e. dictObj2)

How would you:

  • efficiently determine the properties of the inner class (Class2)
  • loop through the the properties of the inner class (Class2)
  • loop through the collection of Class1 objects (listObj1) selecting all instances of the the Class2 property
  • output the collection of Class2 property (e.g. the first iteration would return a collection of MeasurementA, one from each Class1 object).
  • and group the collection by Class1.PropertyA and Class1.PropertyB

Please find below a rough map of the classes involved.

I have been trying to use a LINQ query without success. Any ideas or guidance would be greatly appreciated.

class MainClass {
  List<Class1> listObj1
}

class Class1 {
  // a number of fields including...
  int PropertyA { get; set; }
  int PropertyB { get; set; }
  Dictionary<int, Class2> dictObj2 { get; set; }
}

class Class2 {
  // a number of fields all of type double...
  double MeasurementA { get; set; }
  double MeasurementB { get; set; }
  double MeasurementC { get; set; }
}
Community
  • 1
  • 1
shansen
  • 265
  • 4
  • 14
  • "efficiently determine the properties of the inner class" - by using an `interface`. – Gusdor Jan 14 '14 at 08:38
  • What does your LINQ query look like? – Marcelo Cantos Jan 14 '14 at 08:47
  • 1
    Do you not know the types of these classes before hand? If not then how do you know that the outer class will have a collection of the inner class? It sounds like you're asking how to use Reflection but, if you know the types ahead of time, Reflection should generally be unnecessary. – jmcilhinney Jan 14 '14 at 08:49
  • @jmcilhinney Class1 will always hold multiple Class2 objects. All Class2 attributes will always be present. You are correct, the types are always known ahead of time. I agree Reflection should not be necessary, but I do not know another way to do this. Any suggestions are welcome. – shansen Jan 15 '14 at 05:35

2 Answers2

2

Given data:

MainClass mainClass = new MainClass();
mainClass.listObj1 = new List<Class1>()
{
    new Class1() { 
        dictObj2 = new Dictionary<int,Class2>() {
            { 1, new Class2() { MeasurementA = 2.0, MeasurementB = 3.0, MeasurementC = 4.0 }},
            { 2, new Class2() { MeasurementA = 5.0, MeasurementB = 6.0, MeasurementC = 7.0 }}
        }
    }
};

you can write with LINQ:

var fields = typeof(Class2)
             // Get Properties of the ClassB
             .GetProperties(BindingFlags.Public | BindingFlags.Instance)
             // Map each PropertyInfo into collection of its values from c1.dictObj2
             .SelectMany(pi => mainClass.listObj1
                                        .SelectMany(c1 => c1.dictObj2)
                                        .Select(p => new
                                                 {
                                                   Property = pi.Name,
                                                   Value = pi.GetValue(p.Value)
                                                 }))
             // Group data with respect to the PropertyName
             .GroupBy(x => x.Property, x => x.Value)
             // And create proper dictionary
             .ToDictionary(x => x.Key, x => x.ToList());

and now you have a Dictionary with keys of ClassB property names and values as List of those properties values.

Konrad Kokosa
  • 16,563
  • 2
  • 36
  • 58
  • thank you for your response. Where the returned dictionary also requires a CompositeKey (key based on the Class2 property names and the Class 1 properties, e.g. Struct(c1.PropA, c1.PropB, dict.PropName)), how could this be retrieved? – shansen Sep 29 '14 at 10:45
1

Efficiently determine the properties of the inner class (Class 2)

Regardless of efficiency, there really is only one way you can do it (assuming you mean at runtime) and that's using Reflection.

Loop through the properties of the inner class (Class 2)

foreach (var prop in instance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
    Console.WriteLine(prop.Name);
}

loop through the collection of Class1 objects (listObj1) selecting all instances of the the Class2 property

foreach (var obj in mainClass.listObj1)
{
    var innerClasses = obj.dictObj2.Values;
    // do something with inner classes
}

output the collection of Class2 property (e.g. the first iteration would return a collection of MeasurementA, one from each Class1 object).

foreach (var prop in typeof(Class2).GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
    foreach (var obj in mainClass.listObj1)
    {
        foreach (var innerClass in obj.dictObj2.Values)
        {
            Console.WriteLine(prop.GetValue(innerClass, null));
        }
    }   
}

Not sure why you are so keen on using LINQ here, I think a couple of simple for loops are all you need here.

James
  • 80,725
  • 18
  • 167
  • 237