C# 铸造泛型(协变和逆变?) [英] C# Casting generics (covariance and contravariance?)

查看:28
本文介绍了C# 铸造泛型(协变和逆变?)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆