简体   繁体   English

看到“使用通用方法时无法将表达式转换为类型”时,我在做什么错?

[英]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. systemGKComponentSystem<T>T必须是GKComponent ,因此systemGKComponentSystem<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.

相关问题 通用类型兼容性我在做什么错 - Generic Type Compatibility what am I doing wrong 通用作为参数,我做错了什么? - Generic as parameter, what am I doing wrong? 这个正则表达式我做错了什么? - What am I doing wrong with this regular expression? 无法在通用方法中转换表达式类型错误 - Cannot convert expression type error in generic method 我的SSRS文本框表达式出了什么问题? - What am I doing wrong with my SSRS textbox expression? LINQ Select-CS0411无法从用法中推断出类型实参-我在做什么错? - LINQ Select - CS0411 The type arguments cannot be inferred from the usage - What am I doing wrong? 无法将当前的JSON数组(例如[1,2,3])反序列化为类型……我在做什么错? - Cannot deserialize the current JSON array (e.g. [1,2,3]) into type… what am I doing wrong? WCF - 无法解析[WebGet]符号 - 我做错了什么? - WCF - Cannot resolve [WebGet] symbol - what am I doing wrong? 试图使程序暂停使用协程,我在做什么错? - Trying to make a method pause using coroutines, what am i doing wrong? 我正在尝试将记录插入到对象列表中,但在调用该方法时没有插入任何内容。 我究竟做错了什么? - I am trying to insert records into a an object list but nothing gets inserted when I call the method. What am I doing wrong?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM