Проблема здесь одна из ковариация .
Во-первых, ваш пример слишком сложен. Я удалил немного пуха. Также я добавил несколько диагностических сообщений, освещающих проблему.
class Program
{
static void Main(string[] args)
{
var names = new[] { "Tom", "Dick", "Harry", "Mary", "Jay" };
var query = from n in names
select new C
{
S = n
};
//There IS data in the query result
Debug.Assert(query != null, "result is null");
//but the conversion here makes it return null
var list = query.ToList() as IList<I>;
Console.WriteLine(query.ToList().GetType());
// this assert fires.
Debug.Assert(list != null, "Cast List is null");
}
}
interface I
{
string S { get; set; }
}
class C : I
{
public string S { get; set; }
}
Вывод этой программы:
System.Collections.Generic.List`1[C]
Обратите внимание, что мы пытаемся привести List<C>
к List<I>
, который не работает в C # 3.0.
В C # 4.0 вы сможете это сделать благодаря новой совместной и противоположной дисперсии параметров типа на универсальных интерфейсах.
Кроме того, ваш первоначальный вопрос задавался по поводу IQueryable
, но здесь это не имеет значения: предоставленное вами выражение запроса создает IEnumerable<string>
, а не IQueryable<string>
.
EDIT : Я хочу отметить, что ваше "приведение" с использованием оператора as
технически не приведение, а преобразование типа. Если бы вы использовали приведение, вы бы получили исключение с полезной информацией. Если я изменю на:
var list = (IList<I>)query.ToList();
Я получаю InvalidCastException
с:
Additional information: Unable to cast object of type 'System.Collections.Generic.List1[C]' to type 'System.Collections.Generic.IList
1[I]'.