[英]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.