[英]Register abstract managed classes with generic managing class and preserve one-to-many relationship
我有幾個抽象類,並希望確保“管理器”始終在“托管”類中注冊,以便它們保留一對多關系的雙向知識。 也就是說,Manager知道其擁有的所有Managed類,而Managed類則知道其Manager是誰(如果已向其注冊)。 此外,我希望托管類能夠調用其具體管理器的專業化,而不必進行特殊的強制轉換。 那可能嗎?
我想要這樣的東西,但是遇到編譯問題:
class Program
{
static void Main(string[] args)
{
ConcreteManager manager = new ConcreteManager();
ConcreteManaged managed = new ConcreteManaged() { Name = "Test" };
manager.Add(managed);
managed.Process();
}
}
public abstract class BaseManager<ManagedType>
where ManagedType : BaseManaged
{
protected Dictionary<string, ManagedType> registered = new Dictionary<string, ManagedType>();
public void Add(ManagedType managed)
{
managed.Manager = this; // Cannot implicitly convert type 'BaseManager<ManagedType>' to 'BaseManager<BaseManaged>' (I've tried casting to no avail)
registered.Add(managed.Name, managed);
}
// Other common management tasks
}
public class ConcreteManager : BaseManager<BaseManaged>
{
//specialization stuff, e.g.
public void Refresh() { Console.WriteLine("Refresh Called"); }
}
public abstract class BaseManaged
{
public string Name { get; set; }
public BaseManager<BaseManaged> Manager { get; set; }
}
public class ConcreteManaged : BaseManaged
{
//specialization stuff, e.g.
public void Process()
{
Manager.Refresh();
}
}
如果我如下更改非Program
類,則可以對其進行編譯,但是會出現運行時錯誤(無法將類型為'TestAbstractGenerics.ConcreteManager'的對象轉換為類型為'TestAbstractGenerics.IBaseManager`1 [TestAbstractGenerics.IBaseManaged ]”)。:
public interface IBaseManager<ManagedType>
where ManagedType : IBaseManaged
{
void Add(ManagedType service);
}
public abstract class BaseManager<ManagedType> : IBaseManager<ManagedType>
where ManagedType : IBaseManaged
{
protected Dictionary<string, ManagedType> registered = new Dictionary<string, ManagedType>();
public void Add(ManagedType managed)
{
managed.Manager = (IBaseManager<IBaseManaged>)this;
registered.Add(managed.Name, managed);
}
// Other common management tasks
}
public class ConcreteManager : BaseManager<BaseManaged>
{
//specialization stuff, e.g.
public void Refresh() { Console.WriteLine("Refresh() called"); }
}
public interface IBaseManaged
{
string Name { get; set; }
IBaseManager<IBaseManaged> Manager { get; set; }
}
public abstract class BaseManaged : IBaseManaged
{
public string Name { get; set; }
public IBaseManager<IBaseManaged> Manager { get; set; }
}
public class ConcreteManaged : BaseManaged
{
//specialization stuff, e.g.
public void Process()
{
((ConcreteManager)Manager).Refresh();
}
}
如果我將IBaseManager<IBaseManaged>
更改為dynamic
,則可以從Process()
刪除強制類型轉換,並且一切都按預期進行,但是動態不能與智能感知一起使用,並且我希望能夠執行類型檢查(因此實現者不能將Manager
設置為string
)。 那么,這里的最佳實踐是什么? 有沒有可以遵循的良好模式來保持一對多關系?
是的,在上面,我必須添加一些邏輯以確保在set
BaseManaged.Manager
時從當前的Manager
注銷(如果有)。 為了簡單起見,我在這里避免了這種情況。
編輯:這可行,但是仍然需要在調用其非接口方法之前強制轉換為ConcreteManager
:
class Program
{
static void Main(string[] args)
{
var manager = new ConcreteManager();
var managed = new ConcreteManaged() { Name = "Test"};
manager.Add(managed);
managed.Process();
}
}
public interface IBaseManager<ManagedType>
where ManagedType : IBaseManaged
{
void Add(ManagedType managed);
}
public abstract class BaseManager<ManagedType> : IBaseManager<ManagedType>
where ManagedType : IBaseManaged
{
protected Dictionary<string, ManagedType> registered = new Dictionary<string, ManagedType>();
public void Add(ManagedType managed)
{
managed.Manager = (IBaseManager<IBaseManaged>)this;
registered.Add(managed.Name, managed);
}
// Other common management tasks
}
public class ConcreteManager : BaseManager<IBaseManaged>
{
//specialization stuff, e.g.
public void Refresh() { Console.WriteLine("Refresh() called"); }
}
public interface IBaseManaged
{
string Name { get; set; }
IBaseManager<IBaseManaged> Manager { get; set; }
}
public abstract class BaseManaged : IBaseManaged
{
public string Name { get; set; }
public IBaseManager<IBaseManaged> Manager { get; set; }
}
public class ConcreteManaged : BaseManaged
{
//specialization stuff, e.g.
public void Process()
{
((ConcreteManager)Manager).Refresh();
}
}
我很確定,您想要的那種循環關系不可能實現完全類型安全且沒有強制轉換的情況,因為如果您希望IBaseManaged
也通用,則編譯器最終將陷入無限循環(即, IBaseManaged<T> where T : IBaseManager<?>
),顯然無法指定所需的約束來代替?
。
但是,您可以創建第三個接口/類,該接口/類可以完全表達這種循環約束,這可能會提供替代解決方案。
interface IManagerAdapter<TManager, TManaged>
where TManager : IBaseManager<TManaged>
where TManaged : IBaseManaged<TManager>
IMO,如果您的ConcreteManaged
類無論如何都要通過類型轉換直接了解ConcreteManager
,那么這些類實際上所提供的不只是模式 ,而是具體類型遵循的模式 ,那么抽象就有點破了。 如果您仍然需要特定的具體管理器和托管類型之間的這種緊密耦合,我可能會通過在每個類中添加特定類型來代替Managed
來使它明確,並取消BaseManaged
類,這並沒有太大幫助除了提供Name
之外, Name
足夠簡單,可以在具體實例中重新實現。
public interface IBaseManaged<T> {
string Name { get; set; }
T Manager { get; set; }
}
public class ConcreteManaged : IBaseManaged<ConcreteManager> {
public string Name { get; set; }
public ConcreteManager Manager { get; set; }
public void Process ()
{
Manager.Refresh ();
}
}
對於實現起來可能比Name
更復雜的基本類型,我會選擇一種類似Mixin的方法,在該方法中,您可以在單獨的類中實現該附加功能,而只需在接口中提供一個屬性即可檢索Mixin。 例如,如果所有Manager類都需要考慮注冊所有Managed(與您的Add()
),顯然您不想在每個Manager中重復該功能-但是您可以通過實現一些ManagedRegister<T>
來簡化此方法。說出ManagedRegister<T>
類型(可以說任意話),然后為IBaseManager
類型提供一個Registered
字段以檢索實例。
public interface IBaseManager<T> {
ManagedRegister<T> Registered { get; set; }
}
public class ConcreteManager : IBaseManager<ConcreteManaged> {
public ManagedRegister<ConcreteManaged> Registered { get; set; }
public void Refresh () { Console.WriteLine("Refresh() called"); }
}
您仍然可以從此處的Manager
內的Register中獲得強類型的Managed
實例。
與您的調用代碼相比,更改是代替manager.Add(managed)
,它變為manager.Registered.Add(managed)
,並且您還需要創建ManagedRegister<ConcreteManaged>
的實例以傳遞給ConcreteManager
..也許有點混亂,我建議將其抽象到工廠中,這樣可以防止發生簡單的錯誤,例如忘記將托管實例添加到管理器。 我們可以從上方使用該循環約束以一種類型安全的方式實現它。 (如果可以假定每個Managed / Manager都具有無參數構造函數,則可以使用new()
約束來實現單個實現。否則,您將需要一個抽象工廠並為每種具體類型實現)。
interface IManagerFactory<TManager, TManaged>
where TManager : IBaseManager<TManaged>
where TManaged : IBaseManaged<TManager>
{
TManager Manager { get; }
TManaged Create (string name);
}
public abstract class ManagerFactory<TManager, TManaged>
: IManagerFactory<TManager, TManaged>
where TManager : IBaseManager<TManaged>, new()
where TManaged : IBaseManaged<TManager>, new()
{
TManager manager = new TManager ();
public ManagerFactory () {
manager.Registered = new ManagedRegister<TManaged> ();
}
public TManager Manager { get { return manager; } }
public TManaged Create (string name)
{
TManaged result = new TManaged ();
result.Name = name;
manager.Registered.Add (result.Name, result);
result.Manager = manager;
return result;
}
}
public class ConcreteFactory
: ManagedFactory<ConcreteManager, ConcreteManaged> { }
返回Main,此處的用法略有簡化。
ConcreteFactory f = new ConcreteFactory ();
ConcreteManaged managed = f.CreateManaged ("Test");
managed.Process ();
編輯:
這里將所有通用功能抽象為所謂的“基類”。 此處的主要區別在於,基本類通過Base
屬性組成具體的類,而不是通過Base
屬性繼承而來base.
通常用於呼叫基本成員的前綴。
public class BaseManager<T> {
public Dictionary<string, T> Registered { get; set; }
}
public interface IBaseManager<T> {
BaseManager<T> Base { get; set; }
}
public class ConcreteManager
: IBaseManager<ConcreteManaged> {
public BaseManager<ConcreteManaged> Base { get; set; }
public void Refresh() { Console.WriteLine("Refresh() called"); }
}
public class BaseManaged<T> {
public string Name { get; set; }
public T Manager { get; set; }
}
public interface IBaseManaged<T> {
BaseManaged<T> Base { get; set; }
}
public class ConcreteManaged
: IBaseManaged<ConcreteManager> {
public BaseManaged<ConcreteManager> Base { get; set; }
internal ConcreteManaged () { }
public void Process () {
Base.Manager.Refresh ();
}
}
interface IManagerFactory<TManager, TManaged>
where TManager : IBaseManager<TManaged>
where TManaged : IBaseManaged<TManager> {
TManager Manager { get; }
TManaged Create (string name);
}
public abstract class BaseManagerFactory<TManager, TManaged>
: IManagerFactory<TManager, TManaged>
where TManager : IBaseManager<TManaged>, new()
where TManaged : IBaseManaged<TManager>, new() {
TManager manager = new TManager();
public BaseManagerFactory() {
manager.Base = new BaseManager<TManaged>();
manager.Base.Registered = new Dictionary<string, TManaged>();
}
public TManager Manager { get { return manager; } }
public TManaged Create (string name) {
TManaged result = new TManaged();
result.Base = new BaseManaged<TManager>();
result.Base.Name = name;
manager.Base.Registered.Add (name, result);
result.Base.Manager = manager;
return result;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.