How to iterate properties of an anonymous object in C #?

I want to take an anonymous object as an argument to a method, and then ExpandoObject over its properties to add each property / value to a dynamic ExpandoObject .

So I need to go from

 new { Prop1 = "first value", Prop2 = SomeObjectInstance, Prop3 = 1234 } 

to know the names and values ​​of each property and be able to add them to ExpandoObject .

How to do it?

Side note. This will be done in many of my unit tests (I use it to reorganize a large amount of spam in the configuration), so the performance is somewhat relevant. I don’t know enough about how to reflect, to say for sure, but from what I understood, this is quite high performance, so, if possible, I would prefer to avoid this ...

Follow-up question: As I said, I consider this anonymous object as an argument to a method. What type of data should be used in the method signature? Will all properties be available if I use object ?

+49
c # properties iteration anonymous-types
Apr 07 '10 at 17:23
source share
6 answers
 foreach(var prop in myVar.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) { Console.WriteLine("Name: {0}, Value: {1}",prop.Name, prop.GetValue(myVar,null)); } 
+59
Apr 7 '10 at 17:26
source share

Reflect the anonymous object to get its names and property values, then use ExpandoObject, which is actually a dictionary to populate it. Here is an example expressed as unit test:

  [TestMethod] public void ShouldBeAbleToConvertAnAnonymousObjectToAnExpandoObject() { var additionalViewData = new {id = "myControlId", css = "hide well"}; dynamic result = new ExpandoObject(); var dict = (IDictionary<string, object>)result; foreach (PropertyInfo propertyInfo in additionalViewData.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) { dict[propertyInfo.Name] = propertyInfo.GetValue(additionalViewData, null); } Assert.AreEqual(result.id, "myControlId"); Assert.AreEqual(result.css, "hide well"); } 
+6
Jul 24 '13 at
source share

An alternative approach is to use DynamicObject instead of ExpandoObject , and so you only have the overhead of performing the reflection if you are really trying to access the property from another object.

 public class DynamicForwarder : DynamicObject { private object _target; public DynamicForwarder(object target) { _target = target; } public override bool TryGetMember( GetMemberBinder binder, out object result) { var prop = _target.GetType().GetProperty(binder.Name); if (prop == null) { result = null; return false; } result = prop.GetValue(_target, null); return true; } } 

Now this is only a reflection when you are actually trying to access a property through dynamic get. On the other hand, if you access the same property repeatedly, it must do the reflection every time. This way you can cache the result:

 public class DynamicForwarder : DynamicObject { private object _target; private Dictionary<string, object> _cache = new Dictionary<string, object>(); public DynamicForwarder(object target) { _target = target; } public override bool TryGetMember( GetMemberBinder binder, out object result) { // check the cache first if (_cache.TryGetValue(binder.Name, out result)) return true; var prop = _target.GetType().GetProperty(binder.Name); if (prop == null) { result = null; return false; } result = prop.GetValue(_target, null); _cache.Add(binder.Name, result); // <-------- insert into cache return true; } } 

You can maintain a list of targets for combining their properties and support configuration properties (with a similar override called TrySetMember ) so that you can dynamically set values ​​in the cache dictionary.

Of course, the overhead of thinking is probably not worth the worry, but for large objects this can limit its impact. What could be more interesting is the extra flexibility that this gives you.

+3
Apr 7 2018-10-17T00:
source share

Use Reflection.Emit to create a generic method to populate ExpandoObject.

OR use expressions (perhaps this is only possible in .NET 4).

None of these approaches use reflection when invoked only when setting up a delegate (which obviously needs to be cached).

Here is the Reflection.Emit code to populate the dictionary (I think ExpandoObject is just around the corner);

 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); } 
+1
Apr 7 '10 at 17:26
source share

This is an old question, but now you have to do it with the following code:

 dynamic expObj = new ExpandoObject(); expObj.Name = "James Kirk"; expObj.Number = 34; // print the dynamically added properties // enumerating over it exposes the Properties and Values as a KeyValuePair foreach (KeyValuePair<string, object> kvp in expObj){ Console.WriteLine("{0} = {1} : Type: {2}", kvp.Key, kvp.Value, kvp.Value.GetType()); } 

The result will look like this:

Name = James Kirk: Type: System.String

Number = 34: Type: System.Int32

+1
Nov 22 '16 at 21:04
source share

you need to use reflection .... ( code "borrowed" from this URL )

 using System.Reflection; // reflection namespace // get all public static properties of MyClass type PropertyInfo[] propertyInfos; propertyInfos = typeof(MyClass).GetProperties(BindingFlags.Public | BindingFlags.Static); // sort properties by name Array.Sort(propertyInfos, delegate(PropertyInfo propertyInfo1, PropertyInfo propertyInfo2) { return propertyInfo1.Name.CompareTo(propertyInfo2.Name); }); // write property names foreach (PropertyInfo propertyInfo in propertyInfos) { Console.WriteLine(propertyInfo.Name); } 
0
Apr 7 '10 at 17:25
source share



All Articles