如何动态地将 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
类中?
由于源集合不是键值集合,因此不能使用 []
表示法来访问属性。这就是符号不起作用的原因。您可以尝试使用反射方法(如 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();