如何检查 MethodInfo 是否与泛型类型 T 的委托匹配,其中 T 可以是 Action 或 Func?

3

问题: 如何检查MethodInfo是否与类型为TDelegate相匹配,其中T可以是ActionFunc

以下是一个示例代码,用于从一个Assembly中获取所有静态函数,这些函数应该与类型为TDelegate相匹配:

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);        
            }                
        }

    }        

函数调用示例:

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

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

注意:在不将Delegate.CreateDelegate放入try/catch块中时。

1个回答

4

您只需通过检查参数和返回类型来手动检查签名是否兼容。

例如,以下代码检查将方法分配给委托的兼容性。这不限于 ActionFunc 类型;它可以与任何委托类型一起使用。

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;
}

当然,这段代码没有考虑逆变性;如果您需要以逆变方式工作,则需要检查参数是否可以分配兼容,而不仅仅是相等(就像我做的那样)。
按照防御性编程实践,您可能需要验证类型参数T以检查它是否真的是委托类型。这部分内容由您完成。

你可以添加 : Delegate 约束来降低未接收到委托类型的可能性。 - nalka
1
@nalka 你说得对,最近版本的C#中可以包含委托约束,但当最初提出这个问题时,还没有可用的委托约束。不过还是感谢你提到了这一点。 - Sriram Sakthivel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接