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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With