views:

100

answers:

4

I have some doubt about the title, but I couldn't come up with anything better.

Say I have the following enum

public enum ClassProperties
{
     Primary = 0,
     Secondary = 1,
}

And a class that looks this

public class Test
{
    Primary { get { return _primary; }}
    Secondary { get { return _secondary; }}
    // more irrelevant properties
}

Now somewhere along the line I need to iterate over the enumeration and use each item in it to get the property, like so:

foreach(ClassProperties myProp = Enum.GetValues(typeof(ClassProperties)))
{
    Test t = new Test();
    t.myProp // <- this is what I'm after
    // so if myProp equals Primary,
    // t.Primary is called...
}

This would give you an idea of what I'm trying to do, but trying it makes me feel dirty like a bum who just wet himself. It just doesn't feel right.

+2  A: 

Well you could use Reflection to retrieve the properties. This will then locate the property based on its name.

Test t = new Test();
Type testType = t.GetType();
PropertyInfo[] properties = testType.GetProperties();

For more see GetProperties() method & the returned PropertyInfo type.

Ian
Alright, I'll dive into reflection then :)
Oxymoron
Reflection is fairly straight forward when you get into it. It's fairly powerful although you do suffer a slight performance hit. For the majority of cases though it shouldn't be a problem.
Ian
Yeah, already fixed it :), I'm still quite new to this :)
Oxymoron
And performance isn't an issue in this application. It's a small tool we use to dns servers. Purely internal.
Oxymoron
A: 

Is the enumeration and associated properties dynamic? If they are you will want to use reflection. Otherwise, you could do a simple if-then statement.

Josh Barker
+2  A: 
foreach(ClassProperties myProp in Enum.GetValues(typeof(ClassProperties)))
{
    Test t = new Test();
    PropertyInfo prop = typeof(Test).GetProperty(myProp.ToString());
    // Get
    object value = prop.GetValue(t, null);
    // Set
    prop.SetValue(t, newValue, null);
}
Thomas Levesque
A: 

There are at least two ways of doing this:

1.Reflection and PropertyInfo

var obj = new TestClass();
var allProps = typeof(TestClass).GetProperties();
foreach (var prop in allProps)
{
    // Get propertie value
    object propValue = prop.GetGetMethod().Invoke(obj, null);
    //Set propertie value
    prop.GetSetMethod().Invoke(obj, new object[] { propValue });
}

You should be careful with regard to performance though, just a rough test for a class with two properties setting and getting all the properties 10k times takes 0.06 seconds with reflection and 0.001 seconds if I write it by hand. So the performance hit is pretty drastic

2.Dynamic Methods This method is more complicated but the performance is well worth it. Dynamic methods are methods which the program emits MSIL for at runtime. They get executed by the runtime as if they were created by the compiler (so the speed is very good). Using this method setting and getting 2 properties on a class 10k times took 0.004 seconds (compared to 0.06 seconds with reflection and 0.001 second by hand). Bellow is the code to generate an array of delegates for getters and setters for a certain type. Generating the dynamic can be costly so you should cache the delegates if you intend to use the multiple times (which you probably will).

//Container for getters and setters of a property
public class MyProp
{
    public string PropName { get; set; }
    public Func<object,object> Getter{get;set;}
    public Action<object,object> Setter{get;set;}
}

public static MyProp[] CreatePropertyDelagates (Type type)
{
      var allProps = type.GetProperties();
      var props = new MyProp[allProps.Length];

      for(int i =0;i<allProps.Length;i++)
      {
            var prop = allProps[i];
            // Getter dynamic method the signature would be :
            // object Get(object thisReference)
            // { return ((TestClass)thisReference).Prop; }

            DynamicMethod dmGet = new DynamicMethod("Get", typeof(object), new Type[] { typeof(object), });
            ILGenerator ilGet = dmGet.GetILGenerator();
            // Load first argument to the stack
            ilGet.Emit(OpCodes.Ldarg_0);
            // Cast the object on the stack to the apropriate type
            ilGet.Emit(OpCodes.Castclass, type);
            // Call the getter method passing the object on the stack as the this reference
            ilGet.Emit(OpCodes.Callvirt, prop.GetGetMethod());
            // If the property type is a value type (int/DateTime/..) box the value so we can return it
            if (prop.PropertyType.IsValueType)
            {
                  ilGet.Emit(OpCodes.Box, prop.PropertyType);
            }
            // Return from the method
            ilGet.Emit(OpCodes.Ret);


            // Setter dynamic method the signature would be :
            // object Set(object thisReference, object propValue)
            // { return ((TestClass)thisReference).Prop = (PropType)propValue; }

            DynamicMethod dmSet = new DynamicMethod("Set", typeof(void), new Type[] { typeof(object), typeof(object) });
            ILGenerator ilSet = dmSet.GetILGenerator();
            // Load first argument to the stack and cast it
            ilSet.Emit(OpCodes.Ldarg_0);
            ilSet.Emit(OpCodes.Castclass, type);

            // Load secons argument to the stack and cast it or unbox it
            ilSet.Emit(OpCodes.Ldarg_1);
            if (prop.PropertyType.IsValueType)
            {
                  ilSet.Emit(OpCodes.Unbox_Any,prop.PropertyType);
            }
            else
            {
                  ilSet.Emit(OpCodes.Castclass, prop.PropertyType);
            }
            // Call Setter method and return 
            ilSet.Emit(OpCodes.Callvirt, prop.GetSetMethod());
            ilSet.Emit(OpCodes.Ret);

            // Create the delegates for invoking the dynamic methods and add the to an array for later use
            props[i] =  new MyProp()
            {
                  PropName = prop.Name,
                  Setter = (Action<object, object>)dmSet.CreateDelegate(typeof(Action<object, object>)),
                  Getter = (Func<object, object>)dmGet.CreateDelegate(typeof(Func<object, object>)),
            };

      }
      return props;
}

Invocation of the dynamic methods:

// Should be cahced for further use 
var testClassProps = CreatePropertyDelagates(typeof(TestClass));

var obj = new TestClass();
foreach (var p in testClassProps)
{
      var propValue = p.Getter(obj);
      p.Setter(obj,propValue);
}

Obs: The code above does not deal with properties that have no getter or no setter or are marked as private. This could be easily done by looking at the properties of the ProperyInfo Class and only creating the delegates if apropriate

devilmaster