Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practice instantiating generic delegates and accessing property getters

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?

EDIT:

My concern is performance, 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

I posted the same question on Code Review here, so i will mark this as solved considering the response there

like image 755
anchandra Avatar asked Mar 07 '11 16:03

anchandra


People also ask

Which of the following is the correct way to define generic delegate?

A generic delegate can be defined the same way as a delegate but using generic type parameters or return type. The generic type must be specified when you set a target method. For example, consider the following generic delegate that is used for int and string parameters.

Can delegates be used with generic types?

Delegates defined within a generic class can use the generic class type parameters in the same way that class methods do. Generic delegates are especially useful in defining events based on the typical design pattern because the sender argument can be strongly typed and no longer has to be cast to and from Object.

What are the three types of generic delegates in C#?

Func, Action and Predicate are generic inbuilt delegates present in System namespace. All three can be used with method, anonymous method and lambda expression.


1 Answers

This is something which could be posted on Code Review, and actually, I already posted a similar question. I believe my approach which uses expression trees already improves on your approach.

Example in usage:

Action<object> compatibleExecute =
    DelegateHelper.CreateCompatibleDelegate<Action<object>>( owner, method );

Conversions are done when necessary. The method passed to the function here can have any type of parameter.

UPDATE:

I haven't tested this, but in your case you could try the following:

Func<object> getter =
    DelegateHelper.CreateCompatibleDelegate<Func<object>>( owner, method );

method must be set to the getter you retrieved. owner must be set to the instance of your object. If you want to allow to pass the owner as an argument to the delegate, you'll have to adjust the code. An example is given by Vladimir Matveev as a comment on the article of Jon Skeet.

static Func<T, object, object> MagicMethod<T>(MethodInfo method)    
{    
    var parameter = method.GetParameters().Single();    
    var instance = Expression.Parameter(typeof (T), "instance");
    var argument = Expression.Parameter(typeof (object), "argument");

    var methodCall = Expression.Call(
        instance,
        method,
        Expression.Convert(argument, parameter.ParameterType)
        );

    return Expression.Lambda<Func<T, object, object>>(
        Expression.Convert(methodCall, typeof (object)),
        instance, argument
        ).Compile();
   }
like image 57
Steven Jeuris Avatar answered Oct 07 '22 20:10

Steven Jeuris