簡體   English   中英

在此示例中,如何將具有泛型類型的從同一接口繼承的不同對象存儲在單個變量中?

[英]How can I store different objects inheriting from same interface, with generic types, in a single variable in this example?

假設我有一個數據 model 由 2 個類組成,它們都實現了相同的接口:

    interface IEntity { }
    class EntityTypeA : IEntity { }
    class EntityTypeB : IEntity { }

我有一個通用服務,其中包含這些實體的列表並對其進行處理。 Service 有多種不同的實現,都繼承自 IService,但假設現在只有一個,“Service”。

    interface IService<T> where T : class, IEntity {
        // stuff
        T GetEntity(Func<T, bool> linq);
    }

    class Service<T> : IService<T> where T : class, IEntity {
        // stuff
        IEnumerable<T> _entities;
    }

此時,我可以輕松地為各種實體創建新服務並使用它們。 向它們添加特定類型的新實體,調用方法,將它們取回,而無需手動轉換任何東西。

    IService<EntityTypeA> serviceA = new Service<EntityTypeA>();
    IService<EntityTypeB> serviceB = new Service<EntityTypeB>();

一切都好,但現在我想將所有這些服務存儲在一個地方,這樣我以后可以輕松地獲取我想要的服務,而不必將它們全部保存在一個單獨的變量中。

最終我希望能夠這樣做:

    _manager = new ServiceManager();
    _manager.AddService("A", serviceA);
    _manager.AddService("B", serviceB);
    IService<EntityTypeA> serviceA = _manager.GetService<EntityTypeA>("A");

所以我嘗試了這樣的事情:

class ServiceManager {
        IDictionary<string, IService<IEntity>> _services;

        public void AddService<T>(string key, IService<T> manager) where T : class, IEntity {
            _services[key] = (IService<IEntity>)manager;
        }

        public IService<T> GetService<T>(string key) where T : class, IEntity {
            return (IService<T>)_services[key];
        }
    }

這里的問題是調用 AddService (可能還有 GetService )方法時出現“無效的轉換異常”,我無法將Service<EntityTypeA>轉換並存儲到IService<IEntity>中。 這讓我有點吃驚,因為 EntityTypeA 實現了 IEntity 並且 Service 實現了 IService ...

所以我的問題是:如何將所有這些通用服務存儲在一個變量中,以便我可以通過管理器的一種方法輕松獲取它們? 我希望這個管理器是一個負責管理所有這些服務的單一實例,但我不知道如何在其中保存所有這些通用類。

您不能將Service<EntityTypeA>存儲到IService<IEntity>中,因為IServiceT上是不變的。 泛型類型參數默認情況下是不變的,除非您另外聲明了它們。 Foo<Derived>通常不能分配給Foo<Base> 請參閱這篇文章了解原因。

根據IService// stuff ,您可以潛在地使T covariant ,允許您將IService<EntityTypeA>類型的值(以及因此Service<EntityTypeA> )分配給IService<IEntity>類型的變量。

您可以通過在T上添加一個out修飾符來做到這一點:

interface IService<out T> where T : class, IEntity {
    // stuff
    T GetEntity(Func<T, bool> linq);
}

如果IService具有采用T的方法(除其他外),這將不起作用:

interface IService<out T> where T : class, IEntity {
    // stuff
    T GetEntity(Func<T, bool> linq);
    void Foo(T t); // compiler error
}

因為這會破壞類型安全:

IService<IEntity> s = new Service<EntityTypeA>();
s.Foo(new EntityTypeB()); // breaks type safety! I can now give Service<EntityTypeA> a EntityTypeB object!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM