C#Casting generics(协方差和逆变?)

sam*_*tin 9 .net c# c#-4.0

我需要一些建议/帮助,我再也看不到树上的木头了.

这是一系列直接使用泛型实现某些接口的类.

然后我试图抛出具体类型,例如:

MyGenericObject<SomeObject> _obj;

IMyGenericObject<ISomeObject> _genObj = (IMyGenericObject<ISomeObject>)_obj;
Run Code Online (Sandbox Code Playgroud)

//无效的演员表

我读过一些关于协方差和逆变的文章,但不太清楚为什么这不可能,或者如何绕过它呢?


所以,在这个例子中:

public interface IMyObject<in T> where T : IBaseObject
{
    T Activity { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

不会工作......


....因为,你无法获取并设置Activity属性.

在这个例子中,我需要做:

public interface IMyObject<out T> where T : IBaseObject
    {
        T Activity { get; }
    }
Run Code Online (Sandbox Code Playgroud)

希望对某人有所帮助,并感谢所有人的帮助!

pho*_*oog 11

如果将接口声明为具有covariant(out)参数,则只能这样做.只有在协变使用参数时才能执行此操作.

例如,如果接口IMyGenericObject<T>具有接受T参数的方法,则会阻止您将参数声明为协变.相反,如果有一个返回a的方法,则会T阻止您将参数声明为逆变.

编辑

在回应你对SLaks答案的评论时,我很想重复Eric Lippert所写的关于共同和逆变的所有内容.请参阅http://blogs.msdn.com/b/ericlippert/archive/tags/Covariance+and+Contravariance/以及他在SO中的答案(最近/sf/answers/586614941/)

总结一下:

你不能转发IList<string>,IList<object>因为将a传递给a 是合法FileInfoIList<object>,但将它传递给a 是不合法的IList<string>.

您不能将an转换IList<object>为an IList<string>,因为从a检索项IList<string>并将其分配给字符串引用是合法的,但是IList<object>可能包含FileInfo,而不能将其分配给字符串引用.

编辑2

既然您需要建议,也可以将接口拆分为共变和逆变部分.要继续列表示例,您可以拥有这些接口

public interface ICovariantList<out T>
{
    T this[int index] { get; }
    //...
}

public interface IContravariantList<in T>
{
    T this[int index] { set; }
    void Add(T item);
    //...
}

public class SomeList<T> : ICovariantList<T>, IContravariantList<T>
{
    //...
}
Run Code Online (Sandbox Code Playgroud)

这允许您根据上下文协同或逆转地使用该类.


SLa*_*aks 5

您需要将接口声明为具有covariant(out)泛型参数.

  • 协变是"out"; 逆变是'in`.助记符:"o"表示协变和外出; "n"表示逆变而在. (3认同)
  • @SLaks:可写**协变**属性不是类型安全的.一个可写的**逆变**属性正是逆变的全部. (2认同)