如何检测委托类型之间的兼容性

本文关键字:类型 之间 兼容性 何检测 检测 | 更新日期: 2023-09-27 17:58:32

我有一个这样的测试:

receivingType.IsAssignableFrom(exportingType))

这在大多数情况下都有效,但当涉及的类型是委托类型时,不会返回所需的结果。例如,如果exportingType是Action<object, EventArgs>,receivingType是EventHandler,我希望结果为true,但上面的表达式为false。我要寻找的结果是true,因为这两个委托具有等效的方法签名,并且事实上在C#中实际上是可以相互分配的(尽管我知道这可能是C#语法的魔力)。

因此,我的问题是,对于能够提供所需兼容性结果的委托,等效测试会是什么样子?

如何检测委托类型之间的兼容性

如果您选择忽略参数/返回类型协变/逆变换(自C#2.0以来编译器支持的方差和in/out的通用协变/反方差),要求类型相等,则可以使用:

public static bool AreCompatible(Type delegate1, Type delegate2)
{
    MethodInfo method1 = delegate1.GetMethod("Invoke");
    MethodInfo method2 = delegate1.GetMethod("Invoke");
    return method1.ReturnType == method2.ReturnType &&
           method1.GetParameters().Select(p => p.ParameterType)
                  .SequenceEqual(method2.GetParameters()
                                         .Select(p => p.ParameterType));
}

(如注释中所述,您可能还想检查out/ref参数…)

事实证明,下面的方法对我来说非常有效。虽然我还没有验证它是否能处理泛型类型arg协方差和所有这些复杂性,但我怀疑它能处理,而且我不必做任何操作。:)

internal static bool IsAssignableFrom(Type importingDelegate, Type exportingDelegate)
{
    Type importingDelegate, exportingDelegate; // assigned elsewhere
    MethodInfo exportingDelegateMethod = exportingDelegate.GetMethod("Invoke");
    try
    {
        exportingDelegateMethod.CreateDelegate(importingDelegate, null);
        return true;
    }
    catch (ArgumentException)
    {
        return false;
    }
}

由于我在一个可移植库中,Type.GetMethod不存在,Type.GetRuntimeMethod似乎也不适合。因此,以上内容仅适用于可移植库之外的内容。

对于可移植库,我碰巧已经有了导出方法的MethodInfo,所以我可以跳过GetMethod调用,直接进入CreateDelegate测试。