3

I have a List<CustomObject> which has 3 properties A,B,C and what I need is to transform this List to a Dictionary so the result looks like

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

Pls suggest...

chugh97
  • 9,602
  • 25
  • 89
  • 136

3 Answers3

5
CustomObject instance = new CustomObject();
var dict = instance.GetType().GetProperties()
    .ToDictionary(p => p.Name, p => p.GetValue(instance, null));
Lee
  • 142,018
  • 20
  • 234
  • 287
  • You need `instance.GetType()` to make it work on any type, else quite a nice 'one liner' :) – leppie Nov 05 '10 at 15:26
2

I found the code :) Originally from here.

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);
}

For given type:

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

It produces a delegate equivalent to:

(Foo f) => new Dictionary<string, object>
  {
    { "A", f.A },
    { "B", f.B },
    { "C", f.C },
  };

Disclaimer: Looking at the code now (without testing) there may need to be special handling for valuetypes (instead of just the castclass). Exercise for the reader.

Community
  • 1
  • 1
leppie
  • 115,091
  • 17
  • 196
  • 297
  • @Hath: I was 'forced' to write it for a translation/globalization system to had to reflect fast over WinForm controls. :) – leppie Nov 05 '10 at 15:36
  • awesome! I was just starting to code it this way, but You have managed to do it faster:)THat definately the fastest possible method of doing it:) Although probably not that elegant like a LINQ one:) – luckyluke Nov 05 '10 at 15:38
  • @luckyluke: A thumbsucking estimate would be at least 20 times faster. Nothing is as elegant as LINQ. But you know, in Scheme you could simply write a macro to do this and have it just as fast :) (as long as the type is known at compile time) – leppie Nov 05 '10 at 15:40
0

If I understand correctly what you want to do, you have to use reflrecion on CustomObject to get the property names then simply create the dictionary:

dic.add(propertyName, value);

Liviu Mandras
  • 6,540
  • 2
  • 41
  • 65