简体   繁体   English

C#强制转换泛型(协方差和相反?)

[英]C# Casting generics (covariance and contravariance?)

I need some advice/help on this, I can't see the wood from the trees any more. 我需要一些建议/帮助,我再也看不到树木上的木头了。

It's a straight forward series of classes implementing some interfaces using generics. 这是一系列直接使用泛型实现某些接口的类。

Then I'm trying to cast the concrete types for example: 然后我尝试转换具体类型,例如:

MyGenericObject<SomeObject> _obj;

IMyGenericObject<ISomeObject> _genObj = (IMyGenericObject<ISomeObject>)_obj;

// Invalid cast //无效的转换

I've read some articles about covariance and contravariance but not too clear why this wouldn't be possible, or how to get round it? 我读过一些有关协方差和协方差的文章,但不太清楚为什么这是不可能的,或者如何解决呢?


So, in this example: 因此,在此示例中:

public interface IMyObject<in T> where T : IBaseObject
{
    T Activity { get; set; }
}

wouldn't work... 不会...


....because, you can't get and set the Activity property. ....因为,您无法获取和设置Activity属性。

In this example, I needed to do: 在此示例中,我需要执行以下操作:

public interface IMyObject<out T> where T : IBaseObject
    {
        T Activity { get; }
    }

hope that helps someone, and thanks to all for help! 希望对某人有所帮助,并感谢大家的帮助!

You can only do that if you declare the interface as having a covariant ( out ) parameter. 仅当您声明接口具有协变( out )参数时,才可以这样做。 You can only do that if the parameter is used covariantly. 仅当参数协变使用时才能执行此操作。

For example, if the interface IMyGenericObject<T> has a method taking a T parameter, this prevents you from declaring the parameter as covariant. 例如,如果接口IMyGenericObject<T>具有采用T参数的方法,则这将阻止您将参数声明为协变。 Conversely, if there is a method that returns a T , that prevents you from declaring the parameter as contravariant. 相反,如果存在返回T的方法,则该方法将阻止您将参数声明为反变量。

EDIT 编辑

In response to your comment on SLaks's answer, I'm tempted to repeat everything Eric Lippert has ever written on co- and contravariance. 为了回应您对SLaks答案的评论,我很想重复Eric Lippert曾经写过的关于协方差和反方差的内容。 See http://blogs.msdn.com/b/ericlippert/archive/tags/Covariance+and+Contravariance/ and also his answers in SO (most recently https://stackoverflow.com/a/8380213/385844 ) 参见http://blogs.msdn.com/b/ericlippert/archive/tags/Covariance+and+Contravariance/以及他在SO中的答案(最近https://stackoverflow.com/a/8380213/385844

To summarize: 总结一下:

You can't cast IList<string> to IList<object> because it's legal to pass a FileInfo to an IList<object> , but it is not legal to pass it to an IList<string> . 您不能将IList<string> IList<object>IList<object>因为将FileInfo传递给IList<object>是合法的,但是将其传递给IList<string>是非法的。

You can't cast an IList<object> to an IList<string> , because it's legal to retrieve an item from an IList<string> and assign it to a string reference, but an IList<object> might contain a FileInfo, which can't be assigned to a string reference. 您不能将IList<object> IList<string>转换为IList<string> ,因为从IList<string>检索项目并将其分配给字符串引用是合法的,但是IList<object>可能包含FileInfo,不能分配给字符串引用。

EDIT 2 编辑2

Since you asked for advice, it's also possible to split your interfaces into co- and contravariant parts. 由于您已寻求建议,因此还可以将接口分为协变部分和反变部分。 To continue with the list example, you could have these interfaces 要继续列出示例,您可以使用以下接口

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>
{
    //...
}

This allows you to use the class covariantly or contravariantly, depending on the context. 这使您可以根据上下文使用协变或反变类。

您需要将接口声明为具有协变( out )通用参数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM