简体   繁体   English

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

[英]Generic query with interface as a generic parameter

So I've been fighting against generics lately and don't quite know how to solve this one. 因此,最近我一直在与泛型作斗争,并且不太了解如何解决这一问题。

Basically I have a generic query framework defined as IRxQuery<T> . 基本上,我有一个通用查询框架,定义为IRxQuery<T> My basic model follows one rule: T needs to be an instance type. 我的基本模型遵循一个规则:T必须是实例类型。 Here is the implementation header: 这是实现标头:

public class RxQuery<T> : IRxQuery<T>
        where T : IQueryableObject

One of the notable methods in this class is the Get method, which will deserialize the object got by the query into a T object. 此类中值得注意的方法之一是Get方法,它将查询获得的对象反序列化为T对象。 The method kinda looks like that: 该方法有点像这样:

    protected virtual T Get(IDeserializableObject row)
    {
        var value = Activator.CreateInstance<T>();

        // fill value 

        return value;
    }

Now, I would like to upgrade my query so it would be working with an interface. 现在,我想升级我的查询,以便它可以与接口一起使用。 I am facing the current problem: I have an ISomething interface, implemented by ObjectA and ObjectB . 我正面临当前的问题:我有一个由ObjectAObjectB实现的ISomething接口。 I'd have a case where the query could be any of them and I am trying to fix it, without going adding inheritance. 我有一种情况,其中查询可以是其中的任何一个,而我试图修复它,而无需添加继承。 So I was trying something like: 所以我在尝试类似的东西:

IRxQuery<ISomething> query;
if (isObjectA)
{
   query = new RxQuery<ObjectA>();
}
else
{
   query = new RxQuery<ObjectB>();
}

And of course, you know that won't compile. 当然,您知道那不会编译。 The only solution I thought about so far would be to add a property to the IRxQuery type looking like: 到目前为止,我想到的唯一解决方案是向IRxQuery类型添加一个属性,如下所示:

public Type InstanceType{ get; set; }

And then update the Get method to this: 然后将Get方法更新为此:

protected virtual T Get(IDeserializableObject row)
{
   T value = (T)Activator.CreateInstance(typeof(InstanceType))
}

What approach would you advise me to use to fix this problem? 您会建议我使用哪种方法来解决此问题?

Thank you! 谢谢!

It sounds like you're trying to make this work: 听起来您正在尝试进行以下工作:

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 is a factory method and cannot instantiate an interface using new() . Get是一种工厂方法,无法使用new()实例化接口。 Even if you made T covariant ( IRxQuery<out T> ), you're no closer to it working. 即使您使T协变量( IRxQuery<out T> ),您也离它越来越近。 Your proposed solution of using Activator.CreateInstance (reflection) and having the Type information returned from IRxQuery might work, but regardless it's a poor solution in my opinion (it forfeits some compile-time checks, and requires reflection (obfuscation, if ever needed, could cause this code to crash)). 您提出的使用Activator.CreateInstance (reflection)并从IRxQuery返回Type信息的解决方案可能可行,但是我认为这不是一个糟糕的解决方案(它放弃了一些编译时检查,并且需要进行反射(混淆,如果需要,可能导致此代码崩溃))。

If T must be able to be an interface , then my suggestion is to find a new design such that RxQuery<T> does not need to construct an object of type T . 如果T必须能够成为interface ,那么我的建议是找到一个新设计,使得RxQuery<T>不需要构造T类型的对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM