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;
//无效转换
我读过一些关于协方差和逆变的文章,但不太清楚为什么这是不可能的,或者如何绕过它?
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?
所以,在这个例子中:
public interface IMyObject<in T> where T : IBaseObject
{
T Activity { get; set; }
}
不行...
....因为,您无法获取和设置 Activity 属性.
....because, you can't get and set the Activity property.
在这个例子中,我需要做:
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!
推荐答案
只有将接口声明为具有协变 (out
) 参数时,才能这样做.您只能在协变使用参数时执行此操作.
You can only do that if you declare the interface as having a covariant (out
) parameter. You can only do that if the parameter is used covariantly.
例如,如果接口 IMyGenericObject
有一个采用 T
参数的方法,这会阻止您将参数声明为协变.相反,如果存在返回 T
的方法,则会阻止您将参数声明为逆变.
For example, if the interface IMyGenericObject<T>
has a method taking a T
parameter, this prevents you from declaring the parameter as covariant. Conversely, if there is a method that returns a T
, that prevents you from declaring the parameter as contravariant.
编辑
为了回应您对 SLaks 回答的评论,我很想重复 Eric Lippert 曾经写过的关于协变和逆变的所有内容.请参阅 http://blogs.msdn.com/b/ericlippert/archive/tags/Covariance+and+Contravariance/ 以及他在 SO 中的回答(最近的是 https://stackoverflow.com/a/8380213/385844)
In response to your comment on SLaks's answer, I'm tempted to repeat everything Eric Lippert has ever written on co- and contravariance. 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)
总结:
您不能将 IList
转换为 IList
因为将 FileInfo
传递给 是合法的IList
,但将其传递给 IList
是不合法的.
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
转换为 IList
,因为从 IList
并将其分配给字符串引用,但 IList
可能包含无法分配给字符串引用的 FileInfo.
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.
编辑 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.
这篇关于C# 铸造泛型(协变和逆变?)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!