我希望能够通过Dictionary<int, MyObj>
内的任何属性对MyObj
进行查询和排序。
class MyObj
{
public string Symbol { get; set; }
public string Name { get; set; }
public int AtomicNumber { get; set; }
public int Id { get; set; }
public string toString()
{
return Symbol + " " + Name + " " + AtomicNumber + " " + Id;
}
}
class Program
{
private static void AddToDictionary(Dictionary<int, MyObj> elements,
string symbol, string name, int atomicNumber, int id)
{
MyObj theElement = new MyObj();
theElement.Symbol = symbol;
theElement.Name = name;
theElement.AtomicNumber = atomicNumber;
theElement.Id = id;
elements.Add(key: theElement.Id, value: theElement);
}
private static Dictionary<int, MyObj> BuildDictionary()
{
var elements = new Dictionary<int, MyObj>();
AddToDictionary(elements, "K", "Potassium", 19, 0);
AddToDictionary(elements, "Ca", "Calcium", 20, 1);
AddToDictionary(elements, "Sc", "Scandium", 21, 2);
AddToDictionary(elements, "Ti", "Titanium", 22, 3);
return elements;
}
static List<T> GetListOfProperty<T>(Dictionary<int, MyObj> colBlobs, string property)
{
Type t = typeof(MyObj);
PropertyInfo prop = t.GetProperty(property);
if (prop == null)
{
// throw new Exception(string.Format("Property {0} not found", f.Name.ToLower()));
Console.WriteLine(string.Format("Property {0} not found", property));
return new List<T>();
}
//still need to fix this
return colBlobs.Values
.Select(blob => (T)prop.GetValue(blob))
.OrderBy(x => x)
.ToList();
}
static SortedDictionary<int, MyObj> GetListOfProperty2<T>(Dictionary<int, MyObj> colBlobs, string property)
{
// CODE?
return sortedDict;
}
static void Main(string[] args)
{
Dictionary<int, MyObj> myColl = BuildDictionary();
var res = GetListOfProperty<string>(myColl, "Name");
foreach (var rr in res)
Console.WriteLine(rr.ToString());
//outputs : Which is only one property, the one selected
//--------
//Calcium
//Potassium
//Scandium
//Titanium
var res2 = GetListOfProperty2<string>(myColl, "Name");
//want to output the whole dictionary
//<1, {"Ca", "Calcium", 20,1}
//<0, {"K", "Potassium", 19, 0}
//<2, {"Sc", "Scandium", 21, 2}
//<3, {"Ti", "Titanium", 22, 3}
}
}
由于似乎不清楚我想要什么。我添加了示例输出。我很确定没有办法使这个问题更加清楚。
答案 0 :(得分:2)
要实现您的目标,您可以使用表达式树来构建已编译的lambda,然后在Linq OrderBy()
方法中使用此lambda:
public static class ExpressionHelper
{
public static Func<T, object> GetMemberExpressionFunc<T>(string memberName)
{
var parameter = Expression.Parameter(typeof(T));
Expression source = Expression.PropertyOrField(parameter, memberName);
Expression conversion = Expression.Convert(source, typeof(object));
return Expression.Lambda<Func<T, object>>(conversion, parameter).Compile();
}
}
static void Main(string[] args)
{
Dictionary<int, MyObj> myColl = BuildDictionary();
string property = "AtomicNumber"; // or whatever property you want your dictionary ordered by
var func = ExpressionHelper.GetMemberExpressionFunc<MyObj>(property);
var ordered = myColl.OrderBy(x => func(x.Value));
}
答案 1 :(得分:2)
SortedDictionary
的问题在于只能按Key
进行排序,因此您必须以某种方式使用OrderBy()
:
public static IOrderedEnumerable<KeyValuePair<K, T>> SortByMember<K, T>(this Dictionary<K, T> data, string memberName)
{
Type type = typeof(T);
MemberInfo info = type.GetProperty(memberName) ?? type.GetField(memberName) as MemberInfo;
Func<KeyValuePair<K, T>, object> getter = kvp => kvp.Key;
if (info is PropertyInfo pi)
getter = kvp => pi.GetValue(kvp.Value);
else if (info is FieldInfo fi)
getter = kvp => fi.GetValue(kvp.Value);
return data.OrderBy(getter);
}
这可以处理属性和字段,并且如果成员名称无效,则默认为按键排序。
您可以通过更改返回值将其更改为不排序(如果成员名称无效):
public static IEnumerable<KeyValuePair<K, T>> SortByMember<K, T>(this Dictionary<K, T> data, string memberName)
{
Type type = typeof(T);
MemberInfo info = type.GetProperty(memberName) ?? type.GetField(memberName) as MemberInfo;
if (info == null) return data;
Func<KeyValuePair<K, T>, object> getter = null;
if (info is PropertyInfo pi)
getter = kvp => pi.GetValue(kvp.Value);
else if (info is FieldInfo fi)
getter = kvp => fi.GetValue(kvp.Value);
return data.OrderBy(getter);
}
IMO,如果找不到成员,则返回空字典是错误的。或者,您可以引发异常。
用例:
Dictionary<int, MyObj> myColl = BuildDictionary();
var res = myColl.SortByMember("Name");
foreach (var rr in res)
Console.WriteLine(rr.Value);