6
\$\begingroup\$

I want to create delegates to access properties of different objects without knowing them in advance.

I have the following definitions

public delegate T MyMethod<K, T>(K data);

public static MyMethod<K, T> CreatePropertyGetter<K, T>(PropertyInfo property)
{       
   MethodInfo mi = property.DeclaringType.GetMethod("get_" + property.Name);        
   return (MyMethod<K, T>)Delegate.CreateDelegate(typeof(MyMethod<K, T>), mi);
}

where T can be decimal, string, datetime or int

I have some initializing code that will create MyMethod delegates, based on the reflected properties of my object as follows:

foreach (PropertyInfo property in entityType.GetProperties())
{               
    switch (property.PropertyType.Name)
    {
        case "System.Decimal":
            return CreatePropertyGetter<T, decimal>(property);
        case "System.DateTime":
            return CreatePropertyGetter<T, DateTime>(property);
        case "System.String":
            return CreatePropertyGetter<T, DateTime>(property);
    }
}

Is there a better way to

  1. create property getters?
  2. enumerate through the supported property types hard-coded as strings?

However, performance is an issue, since these delegates will be called frequently (ticking scenario), so any casting will slow it down. While a more elegant solution is desirable, performance is still my main concern

\$\endgroup\$
7
\$\begingroup\$

As my answer on Stack Overflow states, there is a solution which allows you to create a getter delegate for any type, so the entire switch block can be dropped. Personally, I find that the cleanest solution. The only overhead of this approach is the cast from object to the specific type where necessary. (For a getter this would happen only once on the return value.) I'm guessing if you would benchmark this, the result would be negligible.

When you are certain that the only types required are those specified, or that no new types are expected very often, you could still opt to use your current approach. I would apply a few changes however:

  1. Use PropertyInfo.GetGetMethod() to retrieve your MethodInfo for the getter.
  2. Use the type of PropertyType directly to determine which CreatePropertyGetter to call instead of the name of the type.
  3. Use Func<K, T> instead of MyMethod.
  4. Use a Dictionary holding anonymous functions which create the correct delegate for the specified type of the key. This can replace the switch statement.

The last point is possible as follows:

Dictionary<Type, Func<PropertyInfo, object>> getterCreators =
    new Dictionary<Type, Func<PropertyInfo, object>>
    {
        { typeof(string), p => CreatePropertyGetter<T, string>(p) },
        { typeof(DateTime), p => CreatePropertyGetter<T, DateTime>(p) },
        { typeof(decimal), p => CreatePropertyGetter<T, decimal>(p) }
    };

Ofcourse you still have to cast from object to the desired type.

UPDATE:

As Timwi pointed out in the comments, p => CreatePropertyGetter<T, ...>(p) can be further reduced to: CreatePropertyGetter<T, ...>.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Instead of p => CreatePropertyGetter<T, string>(p), I would recommend to write just CreatePropertyGetter<T, string>. \$\endgroup\$
    – Timwi
    Mar 8 '11 at 14:20
  • \$\begingroup\$ @Timwi: Cool, didn't know that worked. \$\endgroup\$ Mar 8 '11 at 14:28
0
\$\begingroup\$

One suggestion is to create type -> type map of all the types you want to support instead of making a switch statement on strings.

\$\endgroup\$
1
  • \$\begingroup\$ Except you can't pass the result of a map lookup as a generic parameter. \$\endgroup\$
    – sepp2k
    Mar 7 '11 at 19:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.