2015-02-06 3 views
0

Итак, я в последнее время борюсь с дженериками и не совсем понимаю, как решить эту проблему.Общий запрос с интерфейсом как общий параметр

В принципе у меня есть общая структура запроса, определенная как 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)) 
} 

Какой подход вы бы проконсультировать меня использовать, чтобы исправить эту проблему?

Спасибо!

+1

Что означает 'IRxQuery'? Не могли бы вы сделать 'T' ковариант? – Lee

ответ

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(). Даже если вы сделали ковариант (IRxQuery<out T>), вы не ближе к нему. Ваше предложенное решение по использованию Activator.CreateInstance (отражение) и имеющее информацию типа, возвращенную с IRxQuery, может работать, но, несмотря на это, это плохое решение, на мой взгляд (оно лишено некоторых проверок времени компиляции и требует отражения (обфускация, если это когда-либо понадобится, может вызвать этот код для сбоя)).

Если T должен быть в состоянии быть interface, то мое предложение, чтобы найти новый дизайн таким образом, что RxQuery<T> не нужно построить объект типа T.

Смежные вопросы