fnsanchez
fnsanchez

Reputation: 43

LINQ - Select a list of a class as fields of the class member

I have, for example, these classes:

public class Person{  
  public string name, surname;  
  public int age;  
  public List<Aspect> aspect; 
}

public class Aspect
{
    public string key;
    public string value;
}

I want a LINQ expression to show the data like this in an object:

NAME, SURNAME, ASPECT1.KEY, ASPECT2.KEY, ...

In other words, the LINQ expression return a list of objects like:

[0]{name="exampleName1", surname="surname1", age="age1", aspectKey1 = "aspectValue11", aspectKey2 = "aspectValue2", ...}
[1]{name="exampleName2", surname="surname2", age="age2", aspectKey1 = "aspectValue12", aspectKey2 = "aspectValue22", ...}

Is this possible with a LINQ select?

Upvotes: 1

Views: 1633

Answers (1)

Reed Copsey
Reed Copsey

Reputation: 564451

You could use something like:

string ReportPerson(Person person)
{
    return string.Format("{0}, {1}, {2}", person.name, person.surname,
        string.Join(", ", person.aspect.SelectMany(a => new[] {a.key, a.value})));
}

Edit in response to your edit:

This is not directly possible, as anonymous types are defined at compile time. A LINQ query which built out a series of properties like this would require knowing how many keys and values existed at compile time, in order to project your data into the appropriate type.

On alternative might be to place your data into a Dictionary<string,string> instead, which would allow you to have an entry for each option:

Dictionary<string,string> ProjectPerson(Person person)
{
    var results = Dictionary<string,string>();
    results.Add("Name", person.name);
    results.Add("Surname", person.surname);
    for (int i=0;i<person.aspect.Count;++i)
    {
         results.Add("aspectKey" + i.ToString(), person.aspect[i].key);             
         results.Add("aspectValue" + i.ToString(), person.aspect[i].value);
    }

    return results;
}

The main difference between your goal and this would be you'd have to access each item via:

string name = projectedPerson["Name"];

Instead of being able to write:

string name = projectedPerson.Name;

If you truly want to use the last option, using dynamic would make this possible:

dynamic ProjectPerson(Person person)
{
    dynamic result = new ExpandoObject();
    var results = result as IDictionary<string, object>();
    results.Add("Name", person.name);
    results.Add("Surname", person.surname);
    for (int i=0;i<person.aspect.Count;++i)
    {
         results.Add("aspectKey" + i.ToString(), person.aspect[i].key);             
         results.Add("aspectValue" + i.ToString(), person.aspect[i].value);
    }

    return result;
}

This will allow you to write:

dynamic projected = ProjectPerson(somePerson);

Console.WriteLine(projected.Name);
Console.WriteLine(projected.aspectKey3); // Assuming there are at least 4 aspects in the person

Upvotes: 9

Related Questions