如何在GetEnumerator <t>中返回动态实体

时间:2019-05-03 09:00:12

标签: c# linq dynamic ienumerable ienumerator

我从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'。'

1 个答案:

答案 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();