具有乘法实现的协变接口的泛型类型推断,如何解决它?

10 c# generics interface covariance

考虑一下这个无用的愚蠢程序:

interface I<out T> { }
class A1 : I<A1> { }
class A2 : A1, I<A2> { }
class B1 { }
class B2 : B1, I<B2> { }
class C1 : I<A1> { }
class C2 : C1, I<A2> { }

static class Program
{
    static void f<T>(I<T> obj)
    {
    }

    static void Main()
    {
        f<A1>(new A2());
        f<A2>(new A2());
        f<B1>(new B2());
        f<B2>(new B2());
        f<A1>(new C2());
        f<A2>(new C2());
    }
}
Run Code Online (Sandbox Code Playgroud)

这表明A2C2实现了I<A1>I<A2>,并B2实现了I<B1>I<B2>.

但是,将此修改为

static void Main()
{
    f(new A2());
    f(new B2());
    f(new C2());
}
Run Code Online (Sandbox Code Playgroud)

表明在第一行和第三行中,f不能从传递的参数推断出泛型类型参数,但在第二行中,它可以是.

我理解编译器在这里做的是什么,因此不需要解释.但是我该如何解决这个问题呢?有没有办法修改它,以便我可以在基类和派生类上定义接口,但在传递派生类时有类型推断?

我想到的是寻找一种方法来"隐藏"基类的实现接口,这样编译器就不会看到它们并使用它们,即使它们确实存在.但是,C#似乎没有提供这样做的选项.

澄清:在我的愚蠢示例程序中,将其自身A1实现I为泛型类型参数.我确实在我的真实代码中有这个,但我也有I使用不同的泛型类型参数实现的类,C1并且C2为此我添加了我的示例代码.

Mar*_*mić 3

使用两个 F 变体(第二个仅用于调用另一个的类型推断)和一个继承自 I 的“覆盖”接口 J,它不执行任何操作,可以像这样完成:

using System;
using System.Threading;


interface I<out T>
{
    void Print();
}

interface J<out T> : I<T> { }

class A : I<C>
{
    void I<C>.Print()
    {
        Console.WriteLine("A: I<C>");
    }
}

class B {}

class C : B { }

class D1 : I<A>
{
    void I<A>.Print()
    {
        Console.WriteLine("D1: I<A>");
    }
}

class D2 : D1, J<B>
{
    void I<B>.Print()
    {
        Console.WriteLine("D2: I<B>");
    }
}

class D3 : D1, J<C>
{
    void I<C>.Print()
    {
        Console.WriteLine("D3: I<C>");
    }
}

class D4 : A, J<B>
{
    void I<B>.Print()
    {
        Console.WriteLine("D4: I<B>");
    }
}

static class Program
{
    static void f<T>(J<T> obj)
    {
        f((I<T>)obj);
    }

    static void f<T>(I<T> obj)
    {
        obj.Print();
    }

    static void Main()
    {

        f<A>(new D2());
        f(new D2());

        f(new D3());

        f(new D4());
        f<C>(new D4());

        Console.ReadKey();
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

D1: I<A>
D2: I<B>
D3: I<C>
D4: I<B>
A: I<C>
Run Code Online (Sandbox Code Playgroud)