我不确定标题是否反映了我的意思,但是......
我们假设我有两个班级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<T>
的小组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();
}
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;
}
}
我想要做的是使Processor
类仅由Foo
对象添加。目前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!
有什么想法吗?
答案 0 :(得分:0)
您的帖子并不清楚您对基本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
注意:我强烈建议不要隐藏班级成员。它并没有像你所说的那样真正影响你的问题(也就是你可以完全抛弃那个细节),但是拥有两个不同的同名属性只是在寻找错误。如果你必须使用隐藏,恕我直言你应该至少让新属性使用隐藏属性。 E.g:
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
属性的分配进行编译时检查,但如果某些代码尝试取消引用{{},则至少会遇到运行时错误{1}}属性作为通用版本,如果由于某种原因由基类型分配了错误的类型。