Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check that MethodInfo matches Delegate of generic type T, where T is either Action or Func?

Question: How to check that MethodInfo matches Delegate of type T, where T is either Action or Func?

Code sample with the use case of getting all static functions out of an Assembly which should match the Delegate of type T:

void AddScriptFunctions<T>(Assembly assembly, Dictionary<string, T> funMap) where T: class
{                                                            
    foreach(Type type in assembly.GetTypes()) 
    {                
        var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Static);
        foreach(MethodInfo method in methods) 
        {                    
            // How to check that MethodInfo can be converted into delegate of type T
            // where T is Func<...> or Action<...>
            if( ........ )
            {
                var function = (T)(object)Delegate.CreateDelegate(typeof(T), method);                    
                funMap.Add(method.Name.ToLower(), function);        
            }                
        }

    }        

Function invocation examples:

var functions = new Dictionary<string, Func<int, int>>();
AddScriptFunctions(Assembly.GetExecutingAssembly(), functions);

var functions2 = new Dictionary<string, Action>();
AddScriptFunctions(Assembly.GetExecutingAssembly(), functions2);

Note: without enclosing Delegate.CreateDelegate into an try/catch block.

like image 417
JBeurer Avatar asked Dec 01 '25 08:12

JBeurer


1 Answers

You should just check whether the signature is compatible manually by inspecting the parameters and return type.

For example following code checks the assignment compatibility of method to delegate. This doesn't restrict the type to Action or Func; It will work with any delegate type.

private void AddScriptFunctions<T>(Assembly assembly, Dictionary<string, T> funMap) where T : class
{
    foreach (Type type in assembly.GetTypes())
    {
        var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Static);
        foreach (MethodInfo method in methods)
        {
            if (IsMethodCompatibleWithDelegate<T>(method)))
            {
                var function = (T) (object) Delegate.CreateDelegate(typeof (T), method);
                funMap.Add(method.Name.ToLower(), function);
            }
        }
    }
}

public bool IsMethodCompatibleWithDelegate<T>(MethodInfo method) where T : class
{
    Type delegateType = typeof(T);
    MethodInfo delegateSignature = delegateType.GetMethod("Invoke");

    bool parametersEqual = delegateSignature
        .GetParameters()
        .Select(x => x.ParameterType)
        .SequenceEqual(method.GetParameters()
            .Select(x => x.ParameterType));

    return delegateSignature.ReturnType == method.ReturnType &&
           parametersEqual;
}

Of course this piece of code doesn't considers the contravariance; If you need this to work contravariantly you need to check whether the parameters are assignment compatible and not just equals(as I did).

Following the defensive programming practice you may need to validate the type parameter T to check if it is really a delegate type. I leave this to you.

like image 123
Sriram Sakthivel Avatar answered Dec 03 '25 23:12

Sriram Sakthivel



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!