使用接口作为通用参数的通用查询

时间:2015-02-06 13:07:38

标签: c# generics

所以我最近一直在与仿制药作斗争,并且不太了解如何解决这个问题。

基本上我有一个定义为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界面,由ObjectAObjectB实施。我有一个案例,查询可以是任何一个,我试图修复它,而不添加继承。所以我尝试了类似的东西:

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

您建议我使用什么方法来解决此问题?

谢谢!

1 个答案:

答案 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}类型的对象}。