我从IEnumerable<T>
实现了课程:
public class MyList<T> : IEnumerable<T>
{
IQueryable Queryable;
public MyList(IQueryable ts)
{
Queryable = ts;
}
public IEnumerator<T> GetEnumerator()
{
foreach (var item in Queryable)
{
yield return (T)item;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
当我从IQuerable
中选择某个属性并执行ToList()
时,它会起作用:
IQueryable propertiesFromClasses = classesIQuerable.Select(a => a.Property);
MyList<MyClass> classes = new MyList<MyClass>(propertiesFromClasses);
var toListResult = classes.ToList();
现在,我要选择动态类型:
IQueryable propertiesFromClasses = classesIQuerable.Select(a => new { SelectedProperty = a.Property });
MyList<MyClass> classes = new MyList<MyClass>(propertiesFromClasses);
var toListResult = classes.ToList();
它在yield return (T)item;
方法的GetEnumerator()
中引发异常:
System.InvalidCastException:'无法转换类型为'<> f__AnonymousType0`1 [System.String]'的类型为'MyClass'。'
答案 0 :(得分:0)
问题显然出在MyClass<T>
的构造函数中。
首先,如果要实现一个表示MyClass<Order>
对象可枚举序列的类Order
,为什么要允许一个接受IQueryable<Student>
的构造函数?
只接受一个Orders
序列,或者至少接受一个可以转换为Orders
的项目序列,会更好吗?
这样,您的编译器就会抱怨,而不是稍后在执行代码时抱怨。
public class MyList<T> : IEnumerable<T>
{
IQueryable<T> queryable;
public MyList(IQueryable<T> ts)
{
this.queryable = ts;
}
public IEnumerator<T> GetEnumerator()
{
return this.Queryable;
}
...
}
如果执行此操作,则编译器将已经抱怨,而不是运行时异常。
您在第二段代码中创建的对象是实现IQueryable<someAnonymousClass>
的对象。调试器将告诉您该对象未实现IQueryable<MyClass>
实现IQueryable<someAnonymousClass>
的对象也实现IQueryable
。但是,可以从此IQueryable
枚举的元素属于someAnonymousClass
类型,这些对象如果没有适当的转换方法就不能转换为MyClass
。
您的第一段代码不会导致此问题,因为您创建的对象实现了IQueryable<MyClass>
,因此枚举器将产生MyClass
个对象,这些对象可以转换为{{1} }没有问题的对象。
但是再次:如果您创建了适当的构造函数,那么您会在编译时而不是在运行时注意到该问题。
您可能真的想设计一个可以容纳MyClass
序列的类,并尝试从中提取所有Students
,或更实际的问题:放置一个序列Orders
并枚举所有Animals
。这样的类可以从任何序列中提取所有Birds:
Birds
尽管可以。我不确定这是否是一个非常有意义的课程。已有一个LINQ函数可以满足您的需求:
var birds = myDbContext.Animals.OfType();