0

Drawing on Loop Through An Objects Properties In C# and Using LINQ to loop through inner class properties in outer class collection

Where you have objects (Phase) in a collection (PhaseRepo), I believe it is possible to specify propertiesOfInterest in the objects (Phase) and create a Dictionary to summarise the properties.

Please find below my attempt in LinqPad. Please assist with the syntax or advise an alternate approach.

Thank you

enum Dir {Up, Dn}

struct BmkKey
{
    public Dir Direction;
    public string DetailType;
}

class Phase
{
    public Dir Direction { get; set; }
    public double StartToTerminationBars { get; set; }
    public double StartToTerminationPriceChange { get; set; }
    public double StartToTerminationGa { get; set; }
    public double NotRequiredProperty { get; set; }
}

class PhaseRepo
{
    public List<Phase> Phases { get; private set; }

    public List<Phase> GetPhases()
    {
        return new List<Phase>()
        { 
            new Phase() { Direction = Dir.Up, StartToTerminationBars = 3.0, StartToTerminationPriceChange = 4.0, StartToTerminationGa = 4.0},
            new Phase() { Direction = Dir.Up, StartToTerminationBars = 6.0, StartToTerminationPriceChange = 8.0, StartToTerminationGa = 4.0},
            new Phase() { Direction = Dir.Dn, StartToTerminationBars = 3.0, StartToTerminationPriceChange = -4.0, StartToTerminationGa = -4.0},
            new Phase() { Direction = Dir.Dn, StartToTerminationBars = 6.0, StartToTerminationPriceChange = -8.0, StartToTerminationGa = -4.0},
        };
    }
}

void Main()
{
    var phaseRepo = new PhaseRepo();
    var phases = phaseRepo.GetPhases();
    //phases.Dump();

    var propertiesOfInterest = typeof (Phase).GetProperties(BindingFlags.Public | BindingFlags.Instance)
    .Where(prop => prop.Name == "StartToTerminationBars" 
        || prop.Name == "StartToTerminationPriceChange" 
        || prop.Name == "StartToTerminationGa")
    .ToList();
    //propertiesOfInterest.Dump();

    // Please Help...
    var test = propertiesOfInterest
        .SelectMany(propertyInfo => phases
            .Select(phase => phase)
            .Select(keyValuePair => new
            {
                phase.Direction,
                keyValuePair.Key,
                keyValuePair.Value
            })
            .Select(arg => new
            {
                Key = new BmkKey
                {
                    Direction,
                    DetailType = propertyInfo.Name
                },
                Value = (double)propertyInfo.GetValue(arg.Value, null)
            }))
        .GroupBy(grp => grp.Key)
        .ToDictionary(grp => grp.Key, grp => x => x.ToList());

    test.Dump();

}

Expected output:

enter image description here

shansen
  • 265
  • 4
  • 14

1 Answers1

0

Solution

Replace the part following

//Please Help...

with the following:

    var test = propertiesOfInterest
        .SelectMany(propertyInfo => phases
            .Select(phase => new
            {
                phase.Direction,
                propertyInfo.Name,
                Value = (double)propertyInfo.GetValue(phase)
            }))
        .GroupBy(o => new BmkKey { Direction = o.Direction, DetailType = o.Name })
        .ToDictionary(grp => grp.Key, grp => grp.Select(x => x.Value));

This essentially gives the expected output shown in your question. (The order is different; adjust using OrderBy() as your needs require.)

Explanation

There were a few issues in your code, but the primary problems were:

  1. The call to GetValue() invoked on the wrong object
  2. The key selector in the .ToDictionary() call.

In addition, the following are not wrong, but unnecessary:

  1. The .Select(phase => phase) call, which does nothing--like a line of code specifying x = x;
  2. Building the key before grouping. Instead, you can simply define the key during the .GroupBy() operation.
Richard II
  • 853
  • 9
  • 31