Generics 协方差和逆变:如何在同一界面中使用两者?

Generics 协方差和逆变:如何在同一界面中使用两者?,generics,interface,covariance,contravariance,variance,Generics,Interface,Covariance,Contravariance,Variance,如何在接口中的泛型类型上使用out参数,并将此类型重用为方法的参数,或作为非协变函数的返回 请参阅示例(我的真实案例是“添加(T项)”,其他是测试): 公共接口ITestAdapter { void Clear();//编译 T GetItemAt(int索引);//编译 void Add(T项);//错误:变量无效:类型参数“T”在“ITestAdapter.Add(T)”上必须相反地有效。“T”是协变的。 IList GetInnerList();//错误:变量无效:类型参数“T”在“ite

如何在接口中的泛型类型上使用out参数,并将此类型重用为方法的参数,或作为非协变函数的返回

请参阅示例(我的真实案例是“添加(T项)”,其他是测试):

公共接口ITestAdapter
{
void Clear();//编译
T GetItemAt(int索引);//编译
void Add(T项);//错误:变量无效:类型参数“T”在“ITestAdapter.Add(T)”上必须相反地有效。“T”是协变的。
IList GetInnerList();//错误:变量无效:类型参数“T”在“iteStatAdapter.GetInnerList()”上必须始终有效。“T”是协变的。
IEnumerable GetInnerAsEnumerable();//编译
}
公共类测试适配器:ITestAdapter
{
公共测试适配器(IList innerList)
{
这。_innerList=innerList;
}
私有只读IList\u innerList;
公共空间清除()
{
此._innerList.Clear();
}
公共作废新增(T项)
{
此._innerList.Add(项);
}
公共T GetItemAt(整数索引)
{
返回此。_innerList[索引];
}
公共IList GetInnerList()
{
返回此。\u innerList;
}
public IEnumerable GetInnerAsEnumerable()
{
返回此。\u innerList;
}
}
公共A类{}
公共类AB:A{}
公开课考试
{
公共静态无效Doy()
{
var list=新列表();
var typed=新约适配器(列表);
var boxed=默认值(ITestAdapter);
boxed=typed;//确定;
}
}

可能与GetInnerList()不完全相同,正如您在我的示例中看到的那样;这只是一个测试,解决方案(GetInnerAsEnumerable())与您引用的文章中的解决方案相同。在我的例子中,我想使用泛型类型作为参数(Add()方法)。推理是一样的。因为类型是逆变的,所以不能将其用作“输入”。这里有一个更好的解释:可能与GetInnerList()不完全相同,正如您在我的示例中看到的那样;这只是一个测试,解决方案(GetInnerAsEnumerable())与您引用的文章中的解决方案相同。在我的例子中,我想使用泛型类型作为参数(Add()方法)。推理是一样的。因为类型是逆变的,所以不能将其用作“输入”。更好的解释是:
public interface ITestAdapter<out T>
{
    void Clear(); // Compile

    T GetItemAt(int index); // Compile

    void Add(T item); // ERROR:  Invalid variance: The type parameter 'T' must be contravariantly valid on 'ITestAdapter<T>.Add(T)'. 'T' is covariant.
    IList<T> GetInnerList(); //ERROR: Invalid variance: The type parameter 'T' must be invariantly valid on 'ITestAdapter<T>.GetInnerList()'. 'T' is covariant.

    IEnumerable<T> GetInnerAsEnumerable(); // Compile
}

public class TestAdapter<T> : ITestAdapter<T>
{
    public TestAdapter(IList<T> innerList)
    {
        this._innerList = innerList;
    }

    private readonly IList<T> _innerList;

    public void Clear()
    {
        this._innerList.Clear();
    }

    public void Add(T item)
    {
        this._innerList.Add(item);
    }

    public T GetItemAt(int index)
    {
        return this._innerList[index];
    }

    public IList<T> GetInnerList()
    {
        return this._innerList;
    }

    public IEnumerable<T> GetInnerAsEnumerable()
    {
        return this._innerList;
    }
}

public class A { }
public class AB : A { }

public class Test
{
    public static void Doy()
    {
        var list = new List<AB>();
        var typed = new TestAdapter<AB>(list);
        var boxed = default(ITestAdapter<A>);
        boxed = typed; // OK;
    }
}