使用 Func<T> 参数时使用逆变的能力差异

Difference in ability to use contravariance when using a Func<T> parameter

我很好奇为什么在C#中允许以下逻辑

private static void Foo(Func<Exception, string> func)
{
    try
    {
        // ...  
    }
    catch (ArgumentException ex)
    {
        func(ex);
    }
}

而这不是

private static void Foo<T>(Func<T, string> func) where T : Exception
{
    try
    {
        // ...  
    }
    catch (ArgumentException ex)
    {
        func(ex);
    }
}

据我了解,由于 Func<in TArg1, out TResult> 委托自 .NET 4.0 起具有逆变参数,因此第一种情况没有问题,但为什么切换到 constrained 泛型改变了编译器应用这种逆变的能力?

您的第一个函数将编译,但是由于 Func 参数的逆变,您只能传递一个 Func 和一个 Exception 超类型的参数,例如

Func<object, string> f = o => o.ToString();
Foo(f);

第二个例子不是这种情况,它要求你传递一个 Func 和一个 Exception 的子类型的参数,例如

Func<InvalidOperationException> f = o => ...

这不安全。