繁体   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