Linq-如何查询Dictionary <int,object>

时间:2019-07-05 17:42:53

标签: c# linq

我希望能够通过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}
    }
  }

由于似乎不清楚我想要什么。我添加了示例输出。我很确定没有办法使这个问题更加清楚。

2 个答案:

答案 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);