从另一个generics类添加generics方法约束
我不确定标题是否反映了我的意思,但……
假设我有两个类, Entity
和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(); }
正如您可能注意到的,上面的类是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; } } }
现在,假设我有Foo
, Bar
和Processor
类:
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不清楚您对基本Entity
和Component
类的约束(如果有)。 所以我不知道你的场景下面是否可行。 也就是说,我相信如果不是,你将无法做你想做的事情,否则编译器就不会知道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版本,则至少会出现运行时错误,如果和何时由于某种原因,基类型分配了错误的类型。