Не уверен, что это лучший способ, но вы можете сделать следующее.
Объект
public class Employee
{
public int ID { get; set; }
public string Place { get; set; }
[IncludeinReport]
public string BusinessVertical { get; set; }
[IncludeinReport]
public string Region { get; set; }
public string Country { get; set; }
[IncludeinReport]
public string BusinessUnit { get; set; }
}
public class IncludeinReport:Attribute
{
}
Пример данных
var list = new List<Employee>
{
new Employee{ID = 1, Region = "Europe", BusinessUnit="Software", BusinessVertical = "Sample1"},
new Employee{ID = 1, Region = "Asia", BusinessUnit="Software", BusinessVertical = "Sample1"},
new Employee{ID = 1, Region = "Asia", BusinessUnit="Hardware", BusinessVertical = "Sample1"},
new Employee{ID = 1, Region = "Europe", BusinessUnit="Software", BusinessVertical = "Sample1"},
new Employee{ID = 1, Region = "Asia", BusinessUnit="Telecom", BusinessVertical = "Sample1"},
new Employee{ID = 1, Region = "Europe", BusinessUnit="Software", BusinessVertical = "Sample1"},
};
Для выше,Вы можете запросить следующим образом.Вам нужно выбрать свойства, которые имеют обязательный атрибут.Этот список свойств используется в вашем запросе к данным.И, наконец, вы используете ExpandoObject для создания требуемого типа.
var properties = typeof(Employee).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(IncludeinReport))).Select(v=>v);
var intermediate = list.OrderBy(c => c.Region).ThenBy(x=>x.BusinessUnit).SelectMany((x,index)=> properties.Select(v=> new {GroupId = index, Dict = new KeyValuePair<string,object>(v.Name, v.GetValue(x))})) ;
var resultList = new List<ExpandoObject>();
foreach(var item in intermediate.GroupBy(x=>x.GroupId))
{
resultList.Add(CreateObject(item.ToList().Select(x=>x.Dict)));
}
Где CreateObject определен как
ExpandoObject CreateObject(IEnumerable<KeyValuePair<string,object>> kvps)
{
dynamic returnValue = new ExpandoObject();
var dict = returnValue as IDictionary<string, object>;
foreach (var kvp in kvps)
{
dict.Add(kvp.Key, kvp.Value);
}
return returnValue;
}
Выход
![enter image description here](https://i.stack.imgur.com/W8z0w.png)
Обновление
Вы можете использовать метод Extension для CreateObject, который сделает его битовым для чтения.
public static class Extensions
{
public static ExpandoObject CreateObject(this IEnumerable<KeyValuePair<string,object>> source)
{
dynamic returnValue = new ExpandoObject();
var dict = returnValue as IDictionary<string, object>;
foreach (var kvp in source)
{
dict.Add(kvp.Key, kvp.Value);
}
return returnValue;
}
}
После чего запрос становится.
var properties = typeof(Employee).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(IncludeinReport))).Select(v=>v);
var intermediate = list.OrderBy(c => c.Region).ThenBy(x=>x.BusinessUnit).SelectMany((x,index)=> properties.Select(v=> new {GroupId = index, Dict = new KeyValuePair<string,object>(v.Name, v.GetValue(x))})) ;
var resultList = intermediate.GroupBy(x=>x.GroupId).Select(x=>x.ToList().Select(c=>c.Dict).CreateObject());