[英]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.