C#实现通用接口的类的工厂

时间:2016-06-27 11:17:53

标签: c# generics factory

我有一个如下定义的界面:

    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();
}

我想要一些类来实现该接口,并且我希望能够使用工厂来注册和创建这些已注册类的实例。我有这个工厂,但似乎没有编译:

    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通过事先知道类型然后转换类型来创建实例的示例,但我真的想要一个创建实例的方法并注册该方法,这样我就不会我必须事先知道每种类型。

我已经看到了关于协变量的一些内容,但我认为这会破坏我的界面,因为我需要一个方法来返回一个可观察的实体集合。

感谢您的帮助。

此致

大卫。

3 个答案:

答案 0 :(得分:3)

当你这样写:

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

答案 1 :(得分:1)

如果不使工厂通用,您就无法实现这一目标:

registerEntitySetMgr并从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; }

中删除T.

制作非泛型类型的字典,然后在运行时进行强制转换。

第一个解决方案:

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;
}

第二个解决方案:

`

答案 2 :(得分:1)

不幸的是,这不会奏效。您声明的词典需要 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强制转换回您的委托类型,如果不是null,则调用委托并返回结果。