Приведение результатов linq-to-sql - PullRequest
3 голосов
/ 20 июля 2010

Работая с интерфейсами, у нас обычно есть var или IQueryable, который собирается возвращать набор объектов данных, которые мы затем приводим к интерфейсу и возвращаем как List или IList, например:

var items =
from t in SomeTable
where t.condition == true
select;
return items.ToList( ).Cast<SomeInterface>( ).ToList( );

ПРИМЕЧАНИЕ: items.Cast () .ToList () скомпилируется, но выдает исключение InvalidCastException во время выполнения.

Есть ли лучший способ?(Я поместил ToList / Cast / ToList в метод расширения, но это не намного лучше ...)

return items.CastToList<SomeClass, SomeInterface>( );

Спасибо!

Ответы [ 3 ]

3 голосов
/ 20 июля 2010

То, что вы делаете, правильно (вы не можете вызвать Cast непосредственно на IQueryable), но это неоптимально, потому что вы создаете 2 списка, когда вам действительно нужен только один. Используйте AsEnumerable вместо первого ToList:

return items.AsEnumerable().Cast<SomeInterface>().ToList();

Вызов AsEnumerable вызовет оценку Cast на IEnumerable, а не IQueryable, поэтому приведение будет выполнено к реальному объекту, возвращенному из БД, а не непосредственно в БД.

2 голосов
/ 20 июля 2010

Какой смысл первого ToList() вызова? Почему не просто items.Cast<SomeInterface>().ToList()?

Альтернативно, вы можете сделать это вместо:

var items = from t in SomeTable
            where t.condition == true
            select (SomeInterface) t;
return items.ToList();

Если t не реализует SomeInterface, он все равно не будет работать во время выполнения.

Это сделает то же самое, но не подведет; скорее это даст вам null, если объект не реализует интерфейс:

var items = from t in SomeTable
            where t.condition == true
            select t as SomeInterface;
return items.ToList();
0 голосов
/ 20 июля 2010

Несколько решений ...

Вместо преобразования данных после их сбора, вы можете рассмотреть вопрос о создании прогноза при его сборе.

return items.Select(x=>x as SomeInterface).ToList();

Если вы делаете это часто, расширениеметод все еще может быть полезным.Это не обязательно должен быть Tolist / Cast / ToList, как вы упомянули.Приведение примет уже IEnumerable, но вы можете создать перегрузку, которая принимает IQueryable, что-то вроде этого (не проверено).

public IEnumerable<TResult> Cast<T, TResult>(this IQueryable<T> input)
{
    return input.AsEnumerable().Cast<TResult>();
}

Это свело бы ваш код к следующему:

return items.Cast<SomeClass, SomeInterface>.ToList();
...