首页 > 解决方案 > IEnumerable.Select() 当属性仅在运行时已知时

问题描述

假设我有一个这样的数据类及其对象列表:

public class DataSet
{
    public int A { get; set; }
    public string B { get; set; }
    public double C { get; set; }
}

var data = new List<DataSet>
{
    new DataSet() { A = 1, B = "One", C = 1.1 },
    new DataSet() { A = 2, B = "Two", C = 2.2 },
    new DataSet() { A = 3, B = "Three", C = 3.3 }
};

我想做一个Select()就行了,根据不同的属性。例如,如果我需要一个 property 列表A,我可以很容易地做到这一点:

var listA = data.Select(x => x.A).ToList();

到目前为止一切都很好。

但是在我的程序中,我只需要执行上述操作,我不知道是否需要AorBC直到运行时的列表。这种选择什么的“知识”存储在字符串列表中,我需要对其进行迭代并仅提取适当的列表。像这样的东西:

// GetKeys() will return the keys that I need to extract.
// So at one time keyList could have "A" and "B", another time "B" and "C" etc.
List<string> keyList = GetKeys();

foreach (var key in keyList)
{
    // What do I do here?
    data.Select(x =>???).ToList();
}

这可能吗?如果它实现了我的目标,我什至可以使用非 LINQ 解决方案。


编辑:澄清要求。

我想要的最终结果是基于上面提到的每个“键”的单独列表。所以,像

List<List<object>>

countin 外部列表将是countof keyList。内部列表将包含与 中一样多的项目DataSet

标签: c#linqselect

解决方案


这可能不是最有效的解决方案,但您可以将反射用于完全动态的解决方案:

private static List<List<object>> SelectDynamicData<T>(IEnumerable<T> data, List<string> properties)
{
    // get the properties only once per call
    // this isn't fast
    var wantedProperties = typeof(T)
        .GetProperties()
        .Where(x => properties.Contains(x.Name))
        .ToArray();

    var result = new Dictionary<string, List<object>>();

    foreach (var item in data)
    {
        foreach (var wantedProperty in wantedProperties)
        {
            if (!result.ContainsKey(wantedProperty.Name))
            {
                result.Add(wantedProperty.Name, new List<object>());
            }

            result[wantedProperty.Name].Add(wantedProperty.GetValue(item));
        }
    }

    return result.Select(x => x.Value).ToList();
}

而且,当然,您需要执行双 foreach 或 LINQ 查询来打印它。例如:

var data = new List<DataSet>
{
    new DataSet() { A = 1, B = "One", C = 1.1 },
    new DataSet() { A = 2, B = "Two", C = 2.2 },
    new DataSet() { A = 3, B = "Three", C = 3.3 }
};

var selectedData = SelectDynamicData(data, new List<string> { "A", "C" });

foreach (var list in selectedData)
{
    foreach (object item in list)
    {
        Console.Write(item + ", ");
    }
    Console.WriteLine();
}

推荐阅读