如何动态地将 List 转换为 List

本文关键字:List MyClass 转换 KeyValue 何动态 动态 | 更新日期: 2023-09-27 18:31:49

如果我有,例如,这个类

public class User{
    int Id;
    string Name;
    short Age;
}

User集合:

public class UserCollection: List<User>{...}

我是否可以从选择哪个属性是Key(或Value)的UserCollection创建List<KeyValue>KeyValue是我的类)?

我尝试使用此代码:

private List<KeyValue> ReadCollection(dynamic collection, string keyName, string valueName)
{
    List<KeyValue> list = new List<KeyValue>();
    for(int i = 0; i < collection.Count; i++)
    {
        dynamic elem = collection[i];
        // I can't use this notation, but only elem.Id
        int key = elem[keyName]; 
        // I can't use this notation, but only elem.Name
        string value = elem[valueName];
        list.Add(new KeyValue(key, value));
     }
     return list;
}
List<KeyValue> list = ReadCollection(userCollection, "Id", "Name");

但它不起作用。可以选择将哪个属性放入我的KeyValue类中?

如何动态地将 List<MyClass> 转换为 List<KeyValue>

由于源集合不是键值集合,因此不能使用 [] 表示法来访问属性。这就是符号不起作用的原因。您可以尝试使用反射方法(如 GetProperty)动态访问值:

var key = elem.GetType().GetProperty(keyName).GetValue(elem, null);
var value = elem.GetType().GetProperty(valueName).GetValue(elem, null);

我至少会使该方法通用,而不是采用动态对象。

然后,可以生成简单的 LINQ 表达式来访问所需的属性,并使用这些表达式获取每个条目的键和值:

private static List<KeyValue> ReadCollection<T>(IList<T> collection, string keyName, string valueName)
{       
    List<KeyValue> list = new List<KeyValue>();
    Func<T, int> keyFunction = GenerateLambda<T, int>(keyName);
    Func<T, string> valueFunction = GenerateLambda<T, string>(valueName);
    for (int i = 0; i < collection.Count; i++)
    {
        T elem = collection[i];
        int key = keyFunction(elem);
        string value = valueFunction(elem);
        list.Add(new KeyValue(key, value));
    }
    return list;
    // or simpler
    //return collection.Select(elem => new KeyValue(keyFunction(elem), valueFunction(elem))).ToList();
}
private static Func<T, TProp> GenerateLambda<T, TProp>(string propertyName)
{
    var p = Expression.Parameter(typeof(T));
    var expr = Expression.Lambda<Func<T, TProp>>(Expression.PropertyOrField(p, propertyName), p);
    return expr.Compile();
}
List<KeyValue> list = ReadCollection(userCollection, "Id", "Name");

在这里工作 .NET 小提琴

我会用Func重写它,而不是所有那些动态的东西。

private List<KeyValue> ReadCollection<T>(IEnumerable<T> collection, Func<T, int> keyFunc, Func<T, string> valueFunc)
{
    List<KeyValue> list = new List<KeyValue>();
    foreach (T elem in collection)
    {
        int key = keyFunc(elem);
        string value = valueFunc(elem);
        list.Add(new KeyValue(key, value));
     }
     return list;
}

你可以这样称呼它:

List<KeyValue> list = ReadCollection<User>(userCollection, u => u.Id, u => u.Name);

好处:

  • 所有代码都是类型化的,因此没有运行时异常;
  • 您拥有完整的智能感知支持;
  • 它几乎支持任何集合类型,也支持 LINQ 枚举。

只需使用"选择"即可更轻松地解决此问题。

List<KeyValue> list = userCollection
                         .Select(x => new KeyValue(x.ID, x.Name))
                         .ToList();
相关文章: