所以,我已经找到了一些问题的几个答案,但我试图结合的两件事似乎把事情放在一起,其他人已经遇到过(或者至少他们&) #39;不要发布它。)
我的目标是能够使用我的代码:
ModelFactory[DataModelX].DataY
我知道我能得到的是:
ModelFactory.Get<DataModelX>.DataY
不可否认,但是在这一点上,我觉得我已经接近并想知道我是否能够得到它。
我目前的课程是:
public class ModelFactory<T> : : IReadOnlyList<IDataModel> where T : IDataModel
private static ModelFactory<IDataModel> _instance;
private ModelFactory() {}
public static ModelFactory<IDataModel> ModelFactory => _instance ?? (_instance = new DataModelFactory<IDataModel>());
private readonly List<IDataModel> _models = new List<IDataModel>();
private T GetHelper(Type type)
{
// check if model exists
foreach (var model in _models.Where(model => model.GetType() == type))
{
// model exists, return it
return (T) model;
}
// model doesn't exist, so we need to create it
var newModel = CreateModel(type);
_models.Add(newModel);
return newModel;
}
public T this[
Type type
] {
get
{
return GetHelper(type);
}
}
DataModels就像这样:
public class DataModel1 : IDataModel
public string Alpha {get; set;}
public int Beta {get; set;}
// etc...
public class DataModel2 : IDataModel
public foo Cat {get; set;}
public foobar Dog {get; set;}
// etc...
等等。
但是,当我尝试输入ModelFactory.ModelFactory[DataModelX].
时,我无法访问ModelFactory。该物业显然是公开的,并包含在适当的类别中。另外,我不能将该类作为参数传递(当然),但我不知道如何调整数组索引上的参数以接受该类作为参数。
Constaints:
答案 0 :(得分:2)
您可以使用typeof(T)
来获取通用参数T
的类型说明。
T newModel = (T)CreateModel(typeof(T));
如果它始终描述与T
相同的类型,则无需额外的Type参数。
此外,您可以使用字典而不是列表来存储模型。
private readonly Dictionary<Type,IDataModel> _models = new Dictionary<Type,IDataModel>();
然后你可以用
获得一个值IDataModel model;
If (!_models.TryGetValue(typeof(T), out model)) {
model = CreateModel(typeof(T));
_models.Add(typeof(T), model);
}
return (T)model;
您的类的泛型类型参数具有误导性,因为它似乎意味着您将为每个模型类型创建一个工厂。放下它。
此外,您无法实施IReadOnlyList<out T>
,因为它需要索引为int
。放弃它。
public class ModelFactory { ... }
现在您有两个选择:
让索引器或普通的Get方法返回IDataModel
,然后转换结果
var m = (MyModelType)factory.Get(typeof(MyModelType));
。
或
var m = (MyModelType)factory[typeof(MyModelType)];
。
声明一个get method with a generic type argument(但该类没有泛型类型参数!)。索引器不能有泛型类型参数。
public T Get<T>() : where T : IDataModel
{
... (same as above)
return (T)model;
}
用
调用它var m = factory.Get<MyModelType>();
答案 1 :(得分:1)
虽然拥有它会很好,但遗憾的是,你所要求的是不可能的。
实现这个工厂有三种可能的方法,其中没有一种可以做你想要的:
1)您拥有的实施,即通用ModelFactory<T> where T : IDataModel
。如上所述,ModelFactory<T>
会强制您限制工厂采用单一类型 - 例如,您必须定义ModelFactory<DataModel1>
,ModelFactory<DataModel2>
等等。&# 39;无论如何都是一个值得怀疑的设计决定,但更重要的是,你只能投入并获得用于创建工厂的具体IDataModel
类型。例如,您无法创建ModelFactory<DataModel1>
并从索引器获取DataModel2
。因此,使用此实现并没有多大意义。
2)非通用ModelFactory
,其索引器返回IDataModel
。这是完全有效的,但您必须转换输出以获得具体类型。因此,使用索引器的调用语法为((DataModel2)ModelFactory[DataModel2]).Cat
或(ModelFactory[DataModel2] as DataModel2).Cat
。在我看来,这比一般的Get<T>()
函数更加丑陋。
3)具有通用索引器的非通用ModelFactory
,例如public T this<T>[Type type] where T : IDataModel
。这与您想要的最接近,但不幸的是,它在当前(C#6)规则下明确禁止。例如,请参阅Why it is not possible to define generic indexers in .NET?。但是,值得注意的是,您仍然无法让编译器自动将type
识别为T
。您无法写public T this<T>[T type]
,因为这会将type
解释为T
类型的对象,也不能写public T this<T>[typeof(T) type]
或类似的内容,因为{{1}是typeof(T)
类型的对象。所以你必须用Type
调用你的索引器(仍然很丑!),并在里面实现运行时检查以确保ModelFactory<DataModel2>[typeof(DataModel2)].Cat
真的是type
类型。
因此,您最干净的选择是使用非通用T
,使用ModelFactory
从内部IDataModel
检索Dictionary<Type, IDataModel>
实现。