将 List<T> 转换为 Dictionary

3

我有一个包含3个属性A、B、C的List<CustomObject>,现在需要将这个List转换成一个Dictionary,使结果如下:

Dictionary<string,object>
(Property name) A = Value of A
(Property name) B = Value of B
(Property name) C = Value of C

请建议...


如果我没记错的话,我在另一个问题中发布了解决方案(使用Reflection.Emit)。那是很久以前的事了,我现在想不起来链接了。如果我找到了会发出来的。 - leppie
嗯,你的表示法有点奇怪,字典的键应该是什么,值又应该是什么? - Albin Sunnanbo
这个字典怎么可能只有三个以上的条目呢? - Hans Passant
结果应该是一个字典列表还是什么? - Michael Goldshteyn
由于所有属性名称都不同,因此应该只有一个字典。 - chugh97
显示剩余6条评论
3个回答

5
CustomObject instance = new CustomObject();
var dict = instance.GetType().GetProperties()
    .ToDictionary(p => p.Name, p => p.GetValue(instance, null));

你需要使用 instance.GetType() 来使其适用于任何类型,否则这将是一个相当不错的“一行代码” :) - leppie

2

我找到了代码 :) 原始来源在这里

static T CreateDelegate<T>(this DynamicMethod dm) where T : class
{
  return dm.CreateDelegate(typeof(T)) as T;
}

static Dictionary<Type, Func<object, Dictionary<string, object>>> cache = 
   new Dictionary<Type, Func<object, Dictionary<string, object>>>();

static Dictionary<string, object> GetProperties(object o)
{
  var t = o.GetType();

  Func<object, Dictionary<string, object>> getter;

  if (!cache.TryGetValue(t, out getter))
  {
    var rettype = typeof(Dictionary<string, object>);

    var dm = new DynamicMethod(t.Name + ":GetProperties", rettype, 
       new Type[] { typeof(object) }, t);

    var ilgen = dm.GetILGenerator();

    var instance = ilgen.DeclareLocal(t);
    var dict = ilgen.DeclareLocal(rettype);

    ilgen.Emit(OpCodes.Ldarg_0);
    ilgen.Emit(OpCodes.Castclass, t);
    ilgen.Emit(OpCodes.Stloc, instance);

    ilgen.Emit(OpCodes.Newobj, rettype.GetConstructor(Type.EmptyTypes));
    ilgen.Emit(OpCodes.Stloc, dict);

    var add = rettype.GetMethod("Add");

    foreach (var prop in t.GetProperties(
      BindingFlags.Instance |
      BindingFlags.Public))
    {
      ilgen.Emit(OpCodes.Ldloc, dict);

      ilgen.Emit(OpCodes.Ldstr, prop.Name);

      ilgen.Emit(OpCodes.Ldloc, instance);
      ilgen.Emit(OpCodes.Ldfld, prop);
      ilgen.Emit(OpCodes.Castclass, typeof(object));

      ilgen.Emit(OpCodes.Callvirt, add);
    }

    ilgen.Emit(OpCodes.Ldloc, dict);
    ilgen.Emit(OpCodes.Ret);

    cache[t] = getter = 
      dm.CreateDelegate<Func<object, Dictionary<string, object>>>();
  }

  return getter(o);
}

对于给定的类型:

class Foo
{
  public string A {get;}
  public int B {get;}
  public bool C {get;}
}

它生成一个与以下代理相等的委托:
(Foo f) => new Dictionary<string, object>
  {
    { "A", f.A },
    { "B", f.B },
    { "C", f.C },
  };

免责声明:目前查看的代码(未经测试)可能需要对值类型进行特殊处理(而不仅仅是强制转换)。让读者自己思考。


@Hath:我被“迫”为一个翻译/全球化系统编写它,以便快速反映在WinForm控件上。 :) - leppie
太棒了!我刚开始以这种方式编码,但你已经成功更快地完成了它 :) 那绝对是最快的方法 :) 尽管可能不像 LINQ 一样优雅 :) - luckyluke
@luckyluke:拇指估计至少快20倍。 LINQ没有什么比这更优雅的了。但是你知道,在Scheme中,您可以编写一个宏来完成此操作,并且速度也一样快:)(只要在编译时已知类型) - leppie

0
如果我正确理解您想要做什么的话,您需要在CustomObject上使用反射来获取属性名称,然后简单地创建一个字典:
dic.add(propertyName, value);

非常无聊且非常缓慢 :) - leppie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接