如何在 GetEnumerator<T> 中 return 动态实体
How to return dynamic entity in GetEnumerator<T>
我从 IEnumerable<T>
实现了 class :
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();
}
}
当我 select 来自 IQuerable
的一些 属性 并执行 ToList()
时,它有效:
IQueryable propertiesFromClasses = classesIQuerable.Select(a => a.Property);
MyList<MyClass> classes = new MyList<MyClass>(propertiesFromClasses);
var toListResult = classes.ToList();
现在,我想要 select 动态类型:
IQueryable propertiesFromClasses = classesIQuerable.Select(a => new { SelectedProperty = a.Property });
MyList<MyClass> classes = new MyList<MyClass>(propertiesFromClasses);
var toListResult = classes.ToList();
它在 GetEnumerator()
方法的 yield return (T)item;
中抛出异常:
System.InvalidCastException: 'Unable to cast object of type '<>f__AnonymousType0`1[System.String]' 键入 'MyClass'.'
问题明显出在MyClass<T>
的构造函数中。
制作一个合适的构造器
首先,如果你想实现一个 class 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;
}
...
}
如果你这样做了,你的编译器会已经抱怨,而不是运行-time exception。
您在第二段代码中创建的对象是实现 IQueryable<someAnonymousClass>
的对象。你的调试器会告诉你这个对象没有实现 IQueryable<MyClass>
实现 IQueryable<someAnonymousClass>
的对象也实现了 IQueryable
。但是,可以从此 IQueryable
枚举的元素属于 someAnonymousClass
类型,如果没有适当的转换方法,这些对象无法转换为 MyClass
。
你的第一段代码不会导致这个问题,因为你创建的对象实现了IQueryable<MyClass>
,因此枚举器将产生MyClass
个对象,可以转换为MyClass
没有问题的对象。
但是再说一次:如果你做了一个合适的构造函数,你会在编译时注意到这个问题,而不是在 运行 时。
备选方案
可能是你真的想设计一个 class 可以容纳 Students
的序列并尝试从中提取所有 Orders
,或者更现实的问题:放置一个 Animals
的序列并枚举所有 Birds
。这样的 class 可以从任何序列中提取所有 Birds:
public class FilteredEnumerator<T> : IEnumerable<T>
{
public FilteredEnumerator(IQueryable queryable)
{
this.queryable = queryable;
}
private readonly IQueryable queryable;
private IEnumerator<T> GetEnumerator()
{
return this.queryable.OfType<T>();
}
}
虽然这行得通。我不确定这是否是一个非常有意义的 class。已经有一个 LINQ 函数可以执行您想要的操作:
var 鸟 = myDbContext.Animals.OfType();
我从 IEnumerable<T>
实现了 class :
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();
}
}
当我 select 来自 IQuerable
的一些 属性 并执行 ToList()
时,它有效:
IQueryable propertiesFromClasses = classesIQuerable.Select(a => a.Property);
MyList<MyClass> classes = new MyList<MyClass>(propertiesFromClasses);
var toListResult = classes.ToList();
现在,我想要 select 动态类型:
IQueryable propertiesFromClasses = classesIQuerable.Select(a => new { SelectedProperty = a.Property });
MyList<MyClass> classes = new MyList<MyClass>(propertiesFromClasses);
var toListResult = classes.ToList();
它在 GetEnumerator()
方法的 yield return (T)item;
中抛出异常:
System.InvalidCastException: 'Unable to cast object of type '<>f__AnonymousType0`1[System.String]' 键入 'MyClass'.'
问题明显出在MyClass<T>
的构造函数中。
制作一个合适的构造器
首先,如果你想实现一个 class 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;
}
...
}
如果你这样做了,你的编译器会已经抱怨,而不是运行-time exception。
您在第二段代码中创建的对象是实现 IQueryable<someAnonymousClass>
的对象。你的调试器会告诉你这个对象没有实现 IQueryable<MyClass>
实现 IQueryable<someAnonymousClass>
的对象也实现了 IQueryable
。但是,可以从此 IQueryable
枚举的元素属于 someAnonymousClass
类型,如果没有适当的转换方法,这些对象无法转换为 MyClass
。
你的第一段代码不会导致这个问题,因为你创建的对象实现了IQueryable<MyClass>
,因此枚举器将产生MyClass
个对象,可以转换为MyClass
没有问题的对象。
但是再说一次:如果你做了一个合适的构造函数,你会在编译时注意到这个问题,而不是在 运行 时。
备选方案
可能是你真的想设计一个 class 可以容纳 Students
的序列并尝试从中提取所有 Orders
,或者更现实的问题:放置一个 Animals
的序列并枚举所有 Birds
。这样的 class 可以从任何序列中提取所有 Birds:
public class FilteredEnumerator<T> : IEnumerable<T>
{
public FilteredEnumerator(IQueryable queryable)
{
this.queryable = queryable;
}
private readonly IQueryable queryable;
private IEnumerator<T> GetEnumerator()
{
return this.queryable.OfType<T>();
}
}
虽然这行得通。我不确定这是否是一个非常有意义的 class。已经有一个 LINQ 函数可以执行您想要的操作:
var 鸟 = myDbContext.Animals.OfType();