如何在 C# 泛型中将子项转换为父项 class
How to cast child to parent class in c# generics
我有一个 classes:
class AClass : CClass
class BClass : CClass
我需要在下面的代码中使用它们:
POJO class:
class SomeObject<T> where T : CClass
T clazz;
setClass(T clazz){
this.clazz = clazz;
.....
控制器 class:
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(){
....
}
}
所以当我尝试实现它时:
SomeObject<AClass> soA = new....
soA.execute(soA) //exception point
.build()
结果我得到异常:can't cast AClass to CClass
所以我需要使用类似的东西:
class ObjectExecutor{
private SomeObject someObject; //without <> signature
..... ....
但是'c#'编译器不允许这种方式。
如何在 'C#' 中使用通用扩展?
截图:
我有两个 classes 在之间延伸:
接口:
实施中:
以及发生问题的地方:
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
的事情
Covariance
在评论部分讨论了您的问题后,我意识到您需要此处的协方差,因为您分配的 class 比最初指定的要多。 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()));
}
}
Contravariance
反之亦然,当您需要分配比最初指定更少的派生 class 时。
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;
}
}
然后你就可以像这样使用它了:
ISomeObject<DerivedClassA> soA = new SomeRealObject<BaseClass>();
我有一个 classes:
class AClass : CClass
class BClass : CClass
我需要在下面的代码中使用它们:
POJO class:
class SomeObject<T> where T : CClass
T clazz;
setClass(T clazz){
this.clazz = clazz;
.....
控制器 class:
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(){
....
}
}
所以当我尝试实现它时:
SomeObject<AClass> soA = new....
soA.execute(soA) //exception point
.build()
结果我得到异常:can't cast AClass to CClass
所以我需要使用类似的东西:
class ObjectExecutor{
private SomeObject someObject; //without <> signature
..... ....
但是'c#'编译器不允许这种方式。
如何在 'C#' 中使用通用扩展?
截图:
我有两个 classes 在之间延伸:
接口:
实施中:
以及发生问题的地方: 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
Covariance
在评论部分讨论了您的问题后,我意识到您需要此处的协方差,因为您分配的 class 比最初指定的要多。 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()));
}
}
Contravariance
反之亦然,当您需要分配比最初指定更少的派生 class 时。
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;
}
}
然后你就可以像这样使用它了:
ISomeObject<DerivedClassA> soA = new SomeRealObject<BaseClass>();