[英]Adding a generic method constraint from the another generic class
我不确定标题是否反映了我的意思,但......
假设我有两个类, Entity
和Component
:
public abstract class Entity
{
private List<Component> _components = new List<Component>();
public void AddComponent<T>()
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
需要的功能只能由继承到Entity
类的特定类附加/添加。
所以,我添加了一个继承Component
Component<T>
类:
public abstract class Entity
{
private List<Component> _components = new List<Component>();
public void AddComponent<T>()
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<T> : 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<Foo>
{
public override void Update()
{
Owner.FooValue = 10;
}
}
我想要做的是使得只有Foo
对象可以添加Processor
类。 目前AddComponent
忽略它,所以我不知道该怎么做:
var foo = new Foo();
var bar = new Bar();
foo.AddComponent<Processor>(); // OK
bar.AddComponent<Processor>(); // Compiler should give an error at this point
我也试过这样做:
public void AddComponent<T, X>()
where T : Component<X>
where X : Entity
{
T component = (T)Activator.CreateInstance(typeof(T));
component.Owner = this;
_components.Add(component);
}
但是,它需要我明确指定X约束:
foo.AddComponent<Processor, Foo>();
bar.AddComponent<Processor, Bar>(); // Error, but the syntax is weird!
有任何想法吗?
您的帖子不清楚您对基本Entity
和Component
类的约束(如果有)。 所以我不知道你的场景下面是否可行。 也就是说,我相信如果不是,你将无法做你想做的事情,否则编译器就不会知道泛型类型参数。
没有任何其他约束的解决方案是使您的Entity
类通用,并提供子类类型本身作为类型参数:
class Entity { }
class Entity<T> : Entity where T : Entity<T>
{
public void AddComponent<U>(U value) where U : Component<T> { }
}
class Component<T> where T : Entity { }
class Foo : Entity<Foo> { }
class Bar : Entity<Bar> { }
class P : Component<Foo> { }
我知道它看起来很奇怪。 但是你基本上要求一个通用类型依赖的自引用图,而在C#代码中,上面就是这样。
您可以使用类型推断调用AddComponent()
方法(因此不需要通用参数)。 如果您尝试使用错误类型的Component<T>
对象调用它,您将收到编译器错误:
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<T> : Component where T : Entity
{
new public T Owner
{
get { return (T)base.Owner; }
set { base.Owner = value; }
}
}
您不会对非泛型Component.Owner
属性的赋值进行编译时检查,但是如果某些代码尝试将Owner
属性作为通用版本取消引用,则至少会出现运行时错误,如果和何时由于某种原因,基类型分配了错误的类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.