将Linq结果转换为Dictionary的最佳实践

时间:2013-11-14 19:58:20

标签: c# linq collections dictionary windows-phone-8

我知道我们可以使用.ToDictionary(t =&gt; t.Key,t =&gt; t.Value)将linq结果集转换为Dictionary集合,但我正在寻找更多内容。我想将给定的linq结果转换为IEnumerable<Dictionary<string, object>>,这就是我要找的内容:

这是我的linq查询:

   var query = from v in dbContext.Persons
                            where !v.InActive
                            select new
                            {
                                v.PersonId,
                                v.Name,
                                v.DateOfBirth,
                            };
this.Persons = query.ToDictionaryCollection();

这是ToDictionaryCollection的样子:

public static IEnumerable<Dictionary<string, object>> ToDictionaryCollection<T>(this IEnumerable<T> collection) where T : class
        {
            if (collection == null || collection.Count() == 0)
            {
                return new List<Dictionary<string, object>>();
            }
            Type givenType = collection.First().GetType();
            PropertyInfo[] properties = givenType.GetProperties(BindingFlags.Instance | BindingFlags.Public);
            return collection
                      .Select(entity =>
                      {
                          return properties.Select(prop => new { Key = prop.Name, Value = prop.GetValue(entity) }).ToDictionary(prop => prop.Key, prop => prop.Value);
                      });
        }

根据目前的实施情况,我相信在每个实体上使用反射会受到惩罚。有没有更好的方法,使用lambda表达式树或类似的东西?

注意:以上代码适用于Windows Phone 8和Windows Store 8.1应用程序。

谢谢, Binoy

3 个答案:

答案 0 :(得分:0)

看起来你正试图做一些与RouteValueDictionary世界System.Web非常相似的事情。您将无法绕过需要进行反思,但您可能会看到Microsoft通过查看their source code来解决此问题,从而获益。

如果您创建了类似于他们的Dictionary类(例如“DynamicDictionary”),那么您可以将方法更改为:

if (collection == null)
{
    return new List<Dictionary<string, object>>();
}
return collection.Select(e => new DynamicDictionary(e));

当然,我建议让你的方法返回一个IDictionary(甚至IReadOnlyDictionary接口,这样你就不会与特定的字典实现紧密耦合。

答案 1 :(得分:0)

好像您的代码完全符合您的要求。你可以改变一些小事:

变化:

Type givenType = collection.First().GetType();

Type givenType = typeof(T);

并且还改变了这个:

return properties.Select(prop => new { Key = prop.Name, Value = prop.GetValue(entity) }).ToDictionary(prop => prop.Key, prop => prop.Value);

return properties.ToDictionary(prop => prop.Name, prop => prop.GetValue(entity));

如果您尝试在类上定义所有属性并返回其C#名称,则无法避免反射。仅获取您需要的特定属性的值以及在其他位置定义名称(例如在视图中)更有意义。但这种设计选择取决于你。

答案 2 :(得分:0)

您可以为每个属性创建一个getter委托,并重用它们而不是调用prop.GetValue()。 如果您正在迭代的集合足够大,这将是有益的。

var properties = typeof (T).GetProperties(BindingFlags.Instance | BindingFlags.Public)
    .Select(
        p =>
        new
            {
                Name = p.Name,
                Getter = (Func<T, object>) Delegate.CreateDelegate(typeof (Func<T, object>), p.GetGetMethod())
            })
    .ToList();

return collection.Select(i => properties.ToDictionary(p => p.Name, p => p.Getter(i)));