Val*_*kyi 3 c# generics covariance contravariance
我有一个课程:
class AClass : CClass
class BClass : CClass
Run Code Online (Sandbox Code Playgroud)
我需要在以下代码中使用它们:
POJO 类:
class SomeObject<T> where T : CClass
T clazz;
setClass(T clazz){
this.clazz = clazz;
.....
Run Code Online (Sandbox Code Playgroud)
控制器类:
class ObjectExecutor{
private SomeObject<CClass> someObject;
public ObjectExecutor execute(SomeObject<CClass> so){
someObject = so; //exception when so - is the instance of AClass
return this;
}
public void build(){
....
}
}
Run Code Online (Sandbox Code Playgroud)
所以当我尝试实现它时:
SomeObject<AClass> soA = new....
soA.execute(soA) //exception point
.build()
Run Code Online (Sandbox Code Playgroud)
结果我得到了异常: can't cast AClass to CClass
所以我需要使用类似的东西:
class ObjectExecutor{
private SomeObject someObject; //without <> signature
..... ....
Run Code Online (Sandbox Code Playgroud)
但是“c#”编译器不允许这种方式。
截图:
我有两个在以下之间扩展的类:
界面:
实施:
以及发生问题的点:1。
2.
错误:
Arg "1": the type conversion from "MyTest.Terkin.ActionElement<Ranorex.Button>" in "MyTest.Terkin.ActionElement<Ranorex.Adapter>" is impossible (CS1503) - C:\Users\Valeryi\Documents\Ranorex\RanorexStudio\MyTest\Recording1.UserCode.cs:60,23
Run Code Online (Sandbox Code Playgroud)
在评论部分讨论您的问题后,我意识到您需要这里的协方差,因为您分配的派生类比最初指定的更多。Pineapple.Given等待,ActionElement<Adapter>但您正在尝试通过ActionElement<Button>并Button从Adapter. 这意味着我们在这里需要协方差。正如我在评论部分已经告诉您的那样,您可以使用out关键字实现与泛型的协变。请注意,只有接口和委托类型参数可以指定为变体,因此为了实现这一点,我们必须创建一个接口并在我们希望应用协变时使用它。这是代码(我稍微修改了屏幕截图中的代码):
class Actions { }
class Adapter { }
class Button : Adapter { }
// covariant generic interface
interface IActionElement<out T> where T : Adapter
{
T GetAdapter();
}
// covariant generic interface implementation
class ActionElement<T> : IActionElement<T> where T : Adapter
{
T adapter;
public T GetAdapter()
{
return adapter;
}
public ActionElement(T adapter)
{
this.adapter = adapter;
}
}
class Pineapple
{
IActionElement<Adapter> actionElement;
Queue<Actions> queue;
// note that I'm using the IActionElement interface here. Not the class that implements the interface like you do
public Pineapple Given(IActionElement<Adapter> adapter)
{
actionElement = adapter;
queue = new Queue<Actions>();
return this;
}
}
class Program
{
static void Main(string[] args)
{
// now it works
Pineapple pineapple = new Pineapple();
var pineappleClone = pineapple.Given(new ActionElement<Button>(new Button()));
}
}
Run Code Online (Sandbox Code Playgroud)
反之亦然,当您需要分配比最初指定的更少的派生类时。
class BaseClass { }
class DerivedClassA : BaseClass { }
class DerivedClassB : BaseClass { }
interface ISomeObject<in T> where T : BaseClass
{
void SetClass(T clazz);
}
class SomeRealObject<T> : ISomeObject<T> where T : BaseClass
{
T obj;
public void SetClass(T obj)
{
this.obj = obj;
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以像这样使用它:
ISomeObject<DerivedClassA> soA = new SomeRealObject<BaseClass>();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
137 次 |
| 最近记录: |