所以我最近一直在与仿制药作斗争,并且不太了解如何解决这个问题。
基本上我有一个定义为IRxQuery<T>
的通用查询框架。我的基本模型遵循一条规则:T需要是实例类型。这是实现标题:
public class RxQuery<T> : IRxQuery<T>
where T : IQueryableObject
此类中一个值得注意的方法是Get
方法,它将查询获取的对象反序列化为T对象。该方法有点像:
protected virtual T Get(IDeserializableObject row)
{
var value = Activator.CreateInstance<T>();
// fill value
return value;
}
现在,我想升级我的查询,以便它可以使用界面。我遇到了当前的问题:我有一个ISomething
界面,由ObjectA
和ObjectB
实施。我有一个案例,查询可以是任何一个,我试图修复它,而不添加继承。所以我尝试了类似的东西:
IRxQuery<ISomething> query;
if (isObjectA)
{
query = new RxQuery<ObjectA>();
}
else
{
query = new RxQuery<ObjectB>();
}
当然,你知道不会编译。到目前为止,我想到的唯一解决方案是将属性添加到IRxQuery
类型,如下所示:
public Type InstanceType{ get; set; }
然后将Get方法更新为:
protected virtual T Get(IDeserializableObject row)
{
T value = (T)Activator.CreateInstance(typeof(InstanceType))
}
您建议我使用什么方法来解决此问题?
谢谢!
答案 0 :(得分:1)
听起来你正试图让这项工作:
class Program {
static void Main(string[] args) {
//compile error: ISomething must be non-abstract with public
// parameterless constructor
RxQuery<ISomething> something = new RxQuery<ISomething>();
}
}
interface ISomething { };
interface IRxQuery<T> { }
public class RxQuery<T> : IRxQuery<T> where T:new() /*, IDeserializableObject*/ {
//Factory Method Pattern
protected virtual T Get(/*IDeserializableObject row*/) { return new T(); }
}
Get
是工厂方法,无法使用new()
实例化接口。即使你提出T
协变(IRxQuery<out T>
),你就不会更接近它了。您提出的使用Activator.CreateInstance
(反射)和从IRxQuery
返回的类型信息的解决方案可能有效,但不管它在我看来是否是一个糟糕的解决方案(它会丢失一些编译时检查,并需要反射(混淆,如果需要,可能导致此代码崩溃))。
如果T
必须能够成为interface
,那么我的建议是找到一个新设计,RxQuery<T>
不需要构建{{1}类型的对象}。