如何将List <myclass>动态转换为List <keyvalue>?

时间:2016-01-25 12:17:43

标签: c# .net c#-4.0 dynamic

例如,如果我有这个课程

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

以及User

的集合
public class UserCollection: List<User>{...}

我可以从List<KeyValue>创建一个KeyValueUserCollection是我的班级),选择哪个属性为Key(或Value)?

我尝试使用此代码:

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类中的属性吗?

4 个答案:

答案 0 :(得分:1)

好吧,由于源集合不是键值集合,因此您无法使用[]表示法来访问属性。这就是为什么符号不起作用的原因。您可以尝试使用GetProperty之类的反射方法来动态访问该值:

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

答案 1 :(得分:1)

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

然后,您可以生成简单的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");

Working .NET Fiddle here

答案 2 :(得分:0)

我会使用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);

优点:

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

答案 3 :(得分:0)

只需使用Select即可轻松解决此问题。

List<KeyValue> list = userCollection
                         .Select(x => new KeyValue(x.ID, x.Name))
                         .ToList();