我有一个如下定义的界面:
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通过事先知道类型然后转换类型来创建实例的示例,但我真的想要一个创建实例的方法并注册该方法,这样我就不会我必须事先知道每种类型。
我已经看到了关于协变量的一些内容,但我认为这会破坏我的界面,因为我需要一个方法来返回一个可观察的实体集合。
感谢您的帮助。
此致
大卫。
答案 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;
}
或
制作非泛型类型的字典,然后在运行时进行强制转换。
第一个解决方案:
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
,则调用委托并返回结果。