从另一个generics类添加generics方法约束

我不确定标题是否反映了我的意思,但……
假设我有两个类, EntityComponent

 public abstract class Entity { private List _components = new List(); public void AddComponent() where T : Component { T component = (T)Activator.CreateInstance(typeof(T)); component.Owner = this; _components.Add(component); } } public abstract class Component { public Entity Owner { get; protected set; } public abstract void Update(); } 

正如您可能注意到的,上面的类是abstract classes ,意思是不打算直接使用。 但是,在开发的后期阶段,我知道某些Component需要的function只能通过inheritance到Entity类的特定类来附加/添加。

所以,我添加了一个inheritanceComponent的类Component

 public abstract class Entity { private List _components = new List(); public void AddComponent() where T : Component { T component = (T)Activator.CreateInstance(typeof(T)); component.Owner = this; _components.Add(component); } } public abstract class Component { public Entity Owner { get; protected set; } public abstract void Update(); } public abstract class Component : Component { // I hide the base.Owner with new keyword // feel free to suggest me in case there is better approach to do this new public T Owner { get { return (T)base.Owner; } protected set { base.Owner = value; } } } 

现在,假设我有FooBarProcessor类:

 public class Foo : Entity { public int FooValue { get; set; } } public class Bar : Entity { public int BarValue { get; set; } } public class Processor : Component { public override void Update() { Owner.FooValue = 10; } } 

我想要做的是使得只有Foo对象可以添加Processor类。 目前AddComponent忽略它,所以我不知道如何做到这一点:

 var foo = new Foo(); var bar = new Bar(); foo.AddComponent(); // OK bar.AddComponent(); // Compiler should give an error at this point 

我也试过这样做:

 public void AddComponent() where T : Component where X : Entity { T component = (T)Activator.CreateInstance(typeof(T)); component.Owner = this; _components.Add(component); } 

但是,它需要我明确指定X约束:

 foo.AddComponent(); bar.AddComponent(); // Error, but the syntax is weird! 

有任何想法吗?

您的post不清楚您对基本EntityComponent类的约束(如果有)。 所以我不知道你的场景下面是否可行。 也就是说,我相信如果不是,你将无法做你想做的事情,否则编译器就不会知道generics类型参数。

没有任何其他约束的解决方案是使您的Entity类通用,并提供子类类型本身作为类型参数:

 class Entity { } class Entity : Entity where T : Entity { public void AddComponent(U value) where U : Component { } } class Component where T : Entity { } class Foo : Entity { } class Bar : Entity { } class P : Component { } 

我知道它看起来很奇怪。 但是你基本上要求一个通用类型依赖的自引用图,而在C#代码中,上面就是这样。

您可以使用类型推断调用AddComponent()方法(因此不需要通用参数)。 如果您尝试使用错误类型的Component对象调用它,您将收到编译器错误:

 Foo foo = new Foo(); Bar bar = new Bar(); P p = new P(); foo.AddComponent(p); bar.AddComponent(p); // CS0311 

注意:我强烈建议不要隐藏类成员。 它并没有真正影响你提出的问题(即你可以完全抛弃那个细节),但是有两个不同的属性同名只是要求bug。 如果你必须使用隐藏,恕我直言你应该至少让新属性使用隐藏属性。 例如:

 class Component { public Entity Owner { get; protected set; } } class Component : Component where T : Entity { new public T Owner { get { return (T)base.Owner; } set { base.Owner = value; } } } 

您不会对非genericsComponent.Owner属性的赋值进行编译时检查,但是如果某些代码尝试将Owner属性取消引用为generics版本,则至少会出现运行时错误,如果和何时由于某种原因,基类型分配了错误的类型。