2013-11-27 4 views
0

У меня есть один базовый классПреобразование списка базы производной класса

public Enum TestType{ 
    A, 
    B 
} 

public abstract class Base{ 
    public int ID{ get;set;} 
} 

и производный класс

public class Derived1 : Base{ 
    public string Prop1 {get;set;} 
} 
public class Derived2 : Base{ 
    public string Prop2 {get;set;} 
} 

то у меня есть функция, которая возвращает базу

public IQueryable<Base> GetData(TestType type){ 
    switch(type){ 
     case A: 
     return new IQueryable<Derived1>(); 
     case B: 
     return new IQueryable<Derived2>(); 
    } 

} 

Сейчас, к сожалению, один из инструментов, с которыми я работаю, требует фактического типа и не может уйти с прохождением в базовом типе.

Как преобразовать результат возврата из GetData в его фактический тип, а не в базу. Я думал использовать выражения и бросить, но я не могу понять это.

Idealy GetData - это фабрика, которая получает данные, я не ожидаю, что там будет IQueryable < Base>, чтобы содержать список смешанных классов. Я НЕ ЗНАЮ ТИПА В ВРЕМЯ КОМИЛЯ! Я хотел бы иметь функцию от базы до выведенной во время выполнения без необходимости проверять базовый тип, а затем делать листинг (IE - сложение операторов if).

EDIT: добавлен некоторый базовый код, который поможет. Теперь элемент управления, который я использую, говорит, что он не может найти свойство Prop1 на базе (если я передаю в результирующий набор GetData, который возвращает IQueryable), но если я его конвертирую, он отлично работает. проблема в том, что я не знаю точного типа во время компиляции. Я просто знаю, что один из классов будет там.

+0

Я не думаю, что вы можете уйти без фактического броска. Как вы ожидаете иметь список с гибридными элементами? –

+0

не будет гибридных элементов – dbarnes

+0

@dbarnes Не могли бы вы поместить небольшой код в 'IQueryable GetData()', чтобы показать, как могут быть возвращены различные типы данных? Если вам не нужна куча инструкций if, нам нужно увидеть логику того, как генерируются данные, поскольку подобная логика должна быть включена в литье. –

ответ

0

я в конечном итоге делает следующее:

var ds = GetData(...); 
if(ds.Any()){ 
    var m = typeof(Queryable).GetMethod("Cast",BindingFlags.Static | BindingFlags.Public, null,new[] { typeof(IQueryable<Base>) }, null).MakeGenericMethod(ds.First().GetType()); 
    var r = m.Invoke(ds, new[] {ds}); 
} 

Кто-нибудь есть проблемы или видеть проблемы здесь?

+2

Ваша читаемость в этом случае не является хорошей, не говоря уже о том, что это будет иметь боль в королевстве, чтобы поддерживать, особенно если кто-то, кроме вас, должен сделать это ... – IronMan84

+0

@Freerider Я не знал тип при компиляции так что это был единственный путь, если вы знаете тип, то, во всяком случае, используйте другие ответы. – dbarnes

5

LINQ имеет вызов Cast<>, который должен работать на вас, как описано в документе here.

var myList = GetData().Cast<Derived1>();

Или, вы можете даже использовать метод Select расширения следующим образом:

var myList = GetData.Select(data => data as Derived1);

EDIT: На основе вашего последнего вопроса редактирования, я рекомендую вам реализовать Factory pattern. Создайте фабрику, которая вернет определенный объект класса, полностью основанный на передаваемом имени. Эти разные объекты класса должны реализовать определенный интерфейс, который имеет метод GetData(), который возвращает IQueryable этого определенного производного типа. Любая добавленная логика, которую вам нужно будет сделать для вашего инструмента, также может быть выполнена и для этого объекта класса (и быть помещенным в интерфейс, чтобы ваш исходный код тоже мог вызвать его).

Выполнение этого способа позволяет вашему коду определять, какой из них следует использовать динамически во время выполнения, а также позволяет вам следовать принципу открытого закрывания. Если вы когда-либо добавляете больше производных типов, все, что вам нужно сделать, это создать новый объект класса, который реализует интерфейс, убедитесь, что Factory знает, что он существует, а затем просто пусть он запускается.

+0

Да, я знаю, что, но тип не будет известен до выполнения. – dbarnes

+0

Сколько у вас производных классов? – IronMan84

+0

любое число, но на данный момент у меня есть 4, и каждый IQueryable имеет тот же тип, о котором я думал о том, чтобы делать OfType и проверять значение null и продолжать, но я не думаю, что это лучший вариант. – dbarnes

1

Использование дженериков и сделать свой метод GetData родовое:

public IQueryable<T> GetData<T>() where T : Base 
{ 
    var data = ...; //object to return 
    return (IQueryable<T>)data; 
} 

Я думаю, что это делает то, что вы пытаетесь сделать, в конце концов.

+0

Я не знаю тип во время компиляции:/ – dbarnes

+0

Какой тип вы не знаете во время компиляции? Тип, в который вы хотите конвертировать? – sjkm

+0

Я хочу перейти от Base к его основополагающему производному, я ищу в создании выражения, которое делает это, используя отражение на базовом типе, о котором я только думал, что может быть лучший способ. – dbarnes

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