簡體   English   中英

C#類的工廠,實現通用接口

[英]C# Factory of classes that implement generic Interface

我有一個這樣定義的接口:

    public interface IEntitySetMgr<T> {

    /// <summary>
    /// The columns involved in the query. Only fields in those columns
    /// will be retrieved from the db.
    /// </summary>
    List<ColumnInfo> Columns { get; set; }

    /// <summary>
    /// The number of entities found in the last query to db.
    /// </summary>
    int EntityCount { get; }

    bool Init();

    bool Synch( QueryFilter queryFilter = null );

    /// <summary>
    /// Retrieves the entities build from data of db.
    /// </summary>
    ObservableCollection<T> GetEntities();
}

我希望一些類實現該接口,並且希望能夠使用工廠來注冊和創建那些已注冊類的實例。 我有這個Factory,但似乎無法編譯:

    public class EntitySetMgrFactory {

    public delegate IEntitySetMgr<T> EntitySetMgrCreator<T>();

    private Dictionary<string, EntitySetMgrCreator<T>> _creators = 
        new Dictionary<string, EntitySetMgrCreator<T>>();

    private static EntitySetMgrFactory _instance = null;
    public static EntitySetMgrFactory Instance {
        get {

            if( _instance == null ) {

                _instance = new EntitySetMgrFactory();
            }

            return _instance;
        }
    }

    private EntitySetMgrFactory() { }

    public bool registerEntitySetMgr<T>( string setName, EntitySetMgrCreator<T> creator ) {

        if( !_creators.ContainsKey( setName ) ) {

            _creators[setName] = creator;
            return true;
        }

        return false;
    }

    public IEntitySetMgr<T> getEntitySetMgr<T>( string setName ) {

        if( _creators.ContainsKey( setName ) ) {

            return (IEntitySetMgr<T>)( _creators[setName] )();
        }

        return null;
    }
}

它抱怨字典的定義。 如果我按字典中的對象更改T,它不會抱怨,但是會在嘗試將EntitySetMgrCreator添加到字典時抱怨,說沒有可用的轉換。 我嘗試顯式地放置演員表,但也不起作用。

我看過一些示例,這些示例使用Activator通過事先知道類型然后強制轉換類型來創建實例,但是我真的想擁有一個創建實例並注冊該方法的方法,這樣我就不必事先了解每種類型。

我已經看到了一些有關協變量的信息,但是我認為這會破壞接口,因為我需要一種返回可觀察到的實體集合的方法。

謝謝你的幫助。

問候,

大衛。

當您編寫此代碼時:

private Dictionary<string, EntitySetMgrCreator<T>> _creators = 
        new Dictionary<string, EntitySetMgrCreator<T>>();

您實際上沒有T因為您將類定義為EntitySetMgrFactory

您可能必須重新考慮您想怎么做以及您在這里真正想要做什么。 你可以簡單地說

private Dictionary<string, object> _creators = 
        new Dictionary<string, object>();

然后

public IEntitySetMgr<T> getEntitySetMgr<T>( string setName ) {

        if( _creators.ContainsKey( setName ) ) {

            return ((EntitySetMgrCreator<T>) _creators[setName] )();
        }

        return null;
    }

但是對我來說,你的目標是什么還不清楚。

該代碼的另一個問題是您的單例實現不是線程安全的。 請檢查以下內容: http : //csharpindepth.com/Articles/General/Singleton.aspx

如果沒有使工廠通用,就無法實現:

EntitySetMgrFactory<T>並從registerEntitySetMgr刪除T

要么

制作非通用類型的字典,然后在運行時進行向下轉換。

第一個解決方案:

public class EntitySetMgrFactory<T>
{

    public delegate IEntitySetMgr<T> EntitySetMgrCreator<T>();

    private readonly Dictionary<string, EntitySetMgrCreator<T>> _creators = new Dictionary<string, EntitySetMgrCreator<T>>();

    private static EntitySetMgrFactory<T> _instance;
    public static EntitySetMgrFactory<T> Instance => _instance ?? (_instance = new EntitySetMgrFactory<T>());

    private EntitySetMgrFactory() { }

    public bool registerEntitySetMgr(string setName, EntitySetMgrCreator<T> creator)
    {
        if (_creators.ContainsKey(setName)) return false;
        _creators[setName] = creator;
        return true;
    }

    public IEntitySetMgr<T> getEntitySetMgr<T>(string setName) => _creators.ContainsKey(setName) ? (IEntitySetMgr<T>)_creators[setName]() : null;
}

第二種解決方案:

public class EntitySetMgrFactory
{

    public delegate IEntitySetMgr<T> EntitySetMgrCreator<T>();

    private readonly Dictionary<string, object> _creators = new Dictionary<string, object>();

    private static EntitySetMgrFactory _instance;
    public static EntitySetMgrFactory Instance => _instance ?? (_instance = new EntitySetMgrFactory());

    private EntitySetMgrFactory() { }

    public bool registerEntitySetMgr<T>(string setName, EntitySetMgrCreator<T> creator)
    {
        if (_creators.ContainsKey(setName)) return false;
        _creators[setName] = creator;
        return true;
    }

    public IEntitySetMgr<T> getEntitySetMgr<T>(string setName) => _creators.ContainsKey(setName) ? ((EntitySetMgrCreator<T>)_creators[setName])() : null;
}

不幸的是,這行不通。 您聲明的字典需要 T的特定類型。 所以Uno已經是對的。 但是我想通用工廠不是您想要的,因為您可能想要一個為不同類型構建通用類的工廠。

因此,我建議使該字典在工廠內部不是通用的,但在外部應保持其類型安全:

public class EntitySetMgrFactory
{
    public delegate IEntitySetMgr<T> EntitySetMgrCreator<T>();

    private Dictionary<string, object> _creators = 
        new Dictionary<string, object>();

    public bool registerEntitySetMgr<T>(string setName, EntitySetMgrCreator<T> creator)
    {
        if(_creators.ContainsKey(setName)) return false;
        _creators[setName] = creator;
        return true;
    }

    public IEntitySetMgr<T> getEntitySetMgr<T>(string setName)
    {
        return _creators.ContainsKey(setName) 
              ? (_creators[setName] as EntitySetMgrCreator<T>)?.Invoke()
              : null;
    }

    // shortened for clarity, your constructor etc here...
}

因此,在getEntitySetMgr<T>我將字典中的object getEntitySetMgr<T>回您的委托類型,如果此值不為null ,則調用委托並返回結果。

暫無
暫無

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

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