[英]What am I doing wrong when seeing “cannot convert expression to type while using a generic method”?
I have a List<GKComponentSystem<GKComponent>>
and a generic Add<T>()
method with a constraint for T
being a GKComponent
. 我有一个List<GKComponentSystem<GKComponent>>
和一个通用的Add<T>()
方法,其中T
限制为GKComponent
。
Why can't I add an instance of GKComponentSystem<T>
to my list? 为什么不能将GKComponentSystem<T>
的实例添加到列表中? See code snipped below: 请参见下面的代码片段:
List<GKComponentSystem<GKComponent>> _systems = new List<GKComponentSystem<GKComponent>>();
public void AddSystem<T>(int position = -1) where T : GKComponent
{
var system = new GKComponentSystem<T>();
_systems.Add(system);
}
Error: 错误:
Argument #1 cannot convert GameplayKit.GKComponentSystem<T> expression to type GameplayKit.GKComponentSystem<GameplayKit.GKComponent> 参数1无法将GameplayKit.GKComponentSystem <T>表达式转换为类型GameplayKit.GKComponentSystem <GameplayKit.GKComponent>
That's in the line _systems.Add(system)
. 在_systems.Add(system)
。
I thought I knew C#, but this is one of the situations where I'm happy to have StackOverflow - what the heck am I not understanding here? 我以为我知道C#,但这是我很高兴拥有StackOverflow的情况之一-我在这里不了解什么呢?
system
is a GKComponentSystem<T>
and T
must be a GKComponent
, so system
is a GKComponentSystem<GKComponent>
and I should be able to add it to my list. system
是GKComponentSystem<T>
而T
必须是GKComponent
,因此system
是GKComponentSystem<GKComponent>
,我应该可以将其添加到我的列表中。
Here's GKComponentSystem
: 这是GKComponentSystem
:
public class GKComponentSystem<T> : NSObject where T : GKComponent
Its T
is also a GKComponent
... 它的T
也是GKComponent
...
Is this about contravariance (a topic I definitely have to learn more about)? 这是关于协变性的吗(我肯定是必须学习更多的话题)?
Here's a simpler example: 这是一个更简单的示例:
class Parent
{
}
class Child : Parent
{
}
class GenericClass<T>
{
}
Parent p;
p = new Child(); // A child inherits from Parent, so this is allowed.
GenericClass<Parent> gp;
gp = new GenericClass<Child>(); // Not allowed! GenericClass<Child> does not inherit from GenericClass<Parent>
In your example, the fact that T
inherits from GKComponent
, does not translate to a rule that GKComponentSystem<T>
can be converted to GKComponentSystem<GKComponent>
. 在您的示例中, T
继承自GKComponent
的事实并不表示可以将GKComponentSystem<T>
转换为GKComponentSystem<GKComponent>
。
So lets apply this to Lists now. 因此,现在将其应用于列表。
List<Parent> l = new List<Parent>();
l.Add(new Child()); // A child can be converted to a Parent, this is OK
List<GenericClass<Parent>> gl = new List<GenericClass<Parent>>();
gl.Add(new GenericClass<Child>()); // A GenericClass<Child> does not convert to GenericClass<Parent>, so this is not allowed.
If you really want this to work, you can define a generic interface. 如果您确实希望这样做,可以定义一个通用接口。 These allow you to specify generic parameters with out
as follows: 这些使您可以指定通用参数,而out
进行以下操作:
interface IGenericClass<out T>
{
}
class GenericClass<T> : IGenericClass<T>
{
}
IGenericClass<Child> gcChild = new GenericClass<Child>();
IGenericClass<Parent> gcParent = gcChild; // This is allowed!
var l = new List<IGenericClass<Parent>>();
l.Add(new GenericClass<Child>()); // Also allowed
So to apply this to your example: 因此,将其应用于您的示例:
interface IGKComponentSystem<out T>
{
}
class GKComponentSystem<T> : IGKComponentSystem
{
}
List<IGKComponentSystem<GKComponent>> _systems = new List<IGKComponentSystem<GKComponent>();
// Should work from there...
public void AddSystem<T>(int position = -1) where T : GKComponent
{
var system = new GKComponentSystem<T>();
_systems.Add(system);
}
Replacing your custom types with BCL types: 将自定义类型替换为BCL类型:
List<List<object>> _systems = new List<List<object>>();
public void AddSystem<T>(int position = -1) where T : class
{
var system = new List<T>();
_systems.Add(system);
}
Now, suppose this were valid and I were to call AddSystem<string>();
现在,假设这是有效的,我将调用AddSystem<string>();
. 。 This would create a List<string>
, and add it to _systems
. 这将创建一个List<string>
,并将其添加到_systems
。
Now, suppose I call _systems[0].Add(1);
现在,假设我叫_systems[0].Add(1);
. 。 There's nothing preventing this. 没有什么可以阻止这一点。 _systems
is a List<List<object>>
, therefore _systems[0]
is a List<object>
, therefore its Add
method accepts any object. _systems
是一个List<List<object>>
,因此_systems[0]
是一个List<object>
,因此其Add
方法可以接受任何对象。
But what I created was a List<string>
, not a List<object>
. 但是我创建的是一个List<string>
,而不是List<object>
。 It shouldn't be possible to add an int
to it. 不可能在其中添加一个int
。
The only way this can be rejected by the compiler is by making the List<string>
-to- List<object>
conversion invalid. 编译器可以拒绝此方法的唯一方法是使List<string>
-to- List<object>
转换无效。 Or in your case, the GKComponentSystem<T>
to GKComponentSystem<GKComponent>
conversion. 或者,根据您的情况,将GKComponentSystem<T>
GKComponentSystem<GKComponent>
转换为GKComponentSystem<GKComponent>
。
Is this about contravariance (a topic I definitely have to learn more about)? 这是关于协变性的吗(我肯定是必须学习更多的话题)?
Sort of. 有点。 Interface and delegate types can specify that some additional guarantees are made. 接口和委托类型可以指定进行一些其他保证。 The IEnumerable<string>
-to- IEnumerable<object>
conversion safe, and allowed for types that include the appropriate annotation. IEnumerable<string>
到IEnumerable<object>
转换安全,并且允许包含适当注释的类型。 But it's not available for class types, and what you can put in such an interface is a bit restricted, anything that could potentially be unsafe is disallowed. 但是它不适用于类类型,并且您可以在此类接口中添加的内容受到了一些限制,不允许使用任何可能不安全的方法。
If what you want to put in your GKComponentSystem
only allows reads, meaning it doesn't have the problem List
does, you could make an IGKComponentSystem<T>
interface, and store a List<IGKComponentSystem<GKComponent>>
, and add a IGKComponentSystem<T>
instance to that without issues. 如果要放入GKComponentSystem
仅允许读取,这意味着List
没有问题,则可以创建IGKComponentSystem<T>
接口,并存储List<IGKComponentSystem<GKComponent>>
,然后添加IGKComponentSystem<T>
实例到没有问题。
If what you want to put in your GKComponentSystem
also allows writes (such as an Add
method), then the conversion is inherently unsafe and you'll need to re-think your design. 如果要放入GKComponentSystem
也允许写入(例如Add
方法),则转换本质上是不安全的,您需要重新考虑设计。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.