복붙노트

[SQL] 형식화 된 목록에서 IDataReader에 가져 오기

SQL

형식화 된 목록에서 IDataReader에 가져 오기

나는 백만 요소 목록 을 가지고있다. (그것은 실제로 음속 컬렉션입니다 있지만 데이터베이스에서로드되지 않습니다).

다음과 같이 저는 현재 SqlBulkCopy의를 사용하고 있습니다 :

private string FastInsertCollection(string tableName, DataTable tableData)
{
    string sqlConn = ConfigurationManager.ConnectionStrings[SubSonicConfig.DefaultDataProvider.ConnectionStringName].ConnectionString;
    using (SqlBulkCopy s = new SqlBulkCopy(sqlConn, SqlBulkCopyOptions.TableLock))
    {
        s.DestinationTableName = tableName;
        s.BatchSize = 5000;
        s.WriteToServer(tableData);
        s.BulkCopyTimeout = SprocTimeout;
        s.Close();
    }
    return sqlConn;
}

나는 내 컬렉션에서 DataTable을 구축 음속의 MyObjectCollection.ToDataTable ()를 사용합니다. 그러나,이 메모리에서 개체를 복제하고 비효율적이다. 나는 메모리 내 컬렉션을 중복되지 않도록 대신 DataTable을의 IDataReader에를 사용하는 SqlBulkCopy.WriteToServer 방법을 사용하고 싶습니다.

내 목록에서 IDataReader에를 얻을 수있는 가장 쉬운 방법은 무엇입니까? 나는 사용자 정의 데이터 판독기를 구현할 수있는 가정 (여기에 같은 http://blogs.microsoft.co.il/blogs/aviwortzel/archive/2008/05/06/implementing-sqlbulkcopy-in-linq-to-sql.aspx) 그러나 나는 일반적인 코드의 무리를 작성하지 않고 할 수있는 간단한 일이 있어야합니다.

편집하다: 하나 쉽게 개체의 컬렉션에서 IDataReader에를 생성 할 수 표시되지 않습니다.  내가 프레임 워크에 내장 된 뭔가를 기대했다하더라도 현재의 대답을 수락.

해결법

  1. ==============================

    1.이 게시물에 코드에서 최신 버전을 가져옵니다

    이 게시물에 코드에서 최신 버전을 가져옵니다

    일반 시력 코드 이탈처럼 아무것도 : 여기에 꽤 완벽하게 구현되지 않습니다. 당신은 IList를 IEnumerable, IEnumerable을 (에고 된 IQueryable)에 비해 IDataReader에 인스턴스를 할 수 있습니다. 이 독자의 제네릭 형식 매개 변수를 노출 할 강력한 이유가 없다 그것을 생략하여, 나는 IEnumerable을 < 'A> (익명 형식)을 허용 할 수 있습니다. 테스트를 참조하십시오.

    소스, 적은 xmldocs는 몇 테스트를 여기에 포함시킬 짧은 충분하다. xmldocs와 소스의 휴식 및 테스트 Salient.Data에서 여기에있다.

    using System;
    using System.Linq;
    using NUnit.Framework;
    
    namespace Salient.Data.Tests
    {
        [TestFixture]
        public class EnumerableDataReaderEFFixture
        {
            [Test]
            public void TestEnumerableDataReaderWithIQueryableOfAnonymousType()
            {
                var ctx = new NorthwindEntities();
    
                var q =
                    ctx.Orders.Where(o => o.Customers.CustomerID == "VINET").Select(
                        o =>
                        new
                            {
                                o.OrderID,
                                o.OrderDate,
                                o.Customers.CustomerID,
                                Total =
                            o.Order_Details.Sum(
                            od => od.Quantity*((float) od.UnitPrice - ((float) od.UnitPrice*od.Discount)))
                            });
    
                var r = new EnumerableDataReader(q);
                while (r.Read())
                {
                    var values = new object[4];
                    r.GetValues(values);
                    Console.WriteLine("{0} {1} {2} {3}", values);
                }
            }
        }
    }
    
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Data;
    using NUnit.Framework;
    
    namespace Salient.Data.Tests
    {
        public class DataObj
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }
    
        [TestFixture]
        public class EnumerableDataReaderFixture
        {
    
            private static IEnumerable<DataObj> DataSource
            {
                get
                {
                    return new List<DataObj>
                               {
                                   new DataObj {Name = "1", Age = 16},
                                   new DataObj {Name = "2", Age = 26},
                                   new DataObj {Name = "3", Age = 36},
                                   new DataObj {Name = "4", Age = 46}
                               };
                }
            }
    
            [Test]
            public void TestIEnumerableCtor()
            {
                var r = new EnumerableDataReader(DataSource, typeof(DataObj));
                while (r.Read())
                {
                    var values = new object[2];
                    int count = r.GetValues(values);
                    Assert.AreEqual(2, count);
    
                    values = new object[1];
                    count = r.GetValues(values);
                    Assert.AreEqual(1, count);
    
                    values = new object[3];
                    count = r.GetValues(values);
                    Assert.AreEqual(2, count);
    
                    Assert.IsInstanceOf(typeof(string), r.GetValue(0));
                    Assert.IsInstanceOf(typeof(int), r.GetValue(1));
    
                    Console.WriteLine("Name: {0}, Age: {1}", r.GetValue(0), r.GetValue(1));
                }
            }
    
            [Test]
            public void TestIEnumerableOfAnonymousType()
            {
                // create generic list
                Func<Type, IList> toGenericList =
                    type => (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(new[] { type }));
    
                // create generic list of anonymous type
                IList listOfAnonymousType = toGenericList(new { Name = "1", Age = 16 }.GetType());
    
                listOfAnonymousType.Add(new { Name = "1", Age = 16 });
                listOfAnonymousType.Add(new { Name = "2", Age = 26 });
                listOfAnonymousType.Add(new { Name = "3", Age = 36 });
                listOfAnonymousType.Add(new { Name = "4", Age = 46 });
    
                var r = new EnumerableDataReader(listOfAnonymousType);
                while (r.Read())
                {
                    var values = new object[2];
                    int count = r.GetValues(values);
                    Assert.AreEqual(2, count);
    
                    values = new object[1];
                    count = r.GetValues(values);
                    Assert.AreEqual(1, count);
    
                    values = new object[3];
                    count = r.GetValues(values);
                    Assert.AreEqual(2, count);
    
                    Assert.IsInstanceOf(typeof(string), r.GetValue(0));
                    Assert.IsInstanceOf(typeof(int), r.GetValue(1));
    
                    Console.WriteLine("Name: {0}, Age: {1}", r.GetValue(0), r.GetValue(1));
                }
            }
    
            [Test]
            public void TestIEnumerableOfTCtor()
            {
                var r = new EnumerableDataReader(DataSource);
                while (r.Read())
                {
                    var values = new object[2];
                    int count = r.GetValues(values);
                    Assert.AreEqual(2, count);
    
                    values = new object[1];
                    count = r.GetValues(values);
                    Assert.AreEqual(1, count);
    
                    values = new object[3];
                    count = r.GetValues(values);
                    Assert.AreEqual(2, count);
    
                    Assert.IsInstanceOf(typeof(string), r.GetValue(0));
                    Assert.IsInstanceOf(typeof(int), r.GetValue(1));
    
                    Console.WriteLine("Name: {0}, Age: {1}", r.GetValue(0), r.GetValue(1));
                }
            } 
            // remaining tests omitted for brevity
        }
    }
    
    /*!
     * Project: Salient.Data
     * File   : EnumerableDataReader.cs
     * http://spikes.codeplex.com
     *
     * Copyright 2010, Sky Sanders
     * Dual licensed under the MIT or GPL Version 2 licenses.
     * See LICENSE.TXT
     * Date: Sat Mar 28 2010 
     */
    
    
    using System;
    using System.Collections;
    using System.Collections.Generic;
    
    namespace Salient.Data
    {
        /// <summary>
        /// Creates an IDataReader over an instance of IEnumerable&lt;> or IEnumerable.
        /// Anonymous type arguments are acceptable.
        /// </summary>
        public class EnumerableDataReader : ObjectDataReader
        {
            private readonly IEnumerator _enumerator;
            private readonly Type _type;
            private object _current;
    
            /// <summary>
            /// Create an IDataReader over an instance of IEnumerable&lt;>.
            /// 
            /// Note: anonymous type arguments are acceptable.
            /// 
            /// Use other constructor for IEnumerable.
            /// </summary>
            /// <param name="collection">IEnumerable&lt;>. For IEnumerable use other constructor and specify type.</param>
            public EnumerableDataReader(IEnumerable collection)
            {
                // THANKS DANIEL!
                foreach (Type intface in collection.GetType().GetInterfaces())
                {
                    if (intface.IsGenericType && intface.GetGenericTypeDefinition() == typeof (IEnumerable<>))
                    {
                        _type = intface.GetGenericArguments()[0]; 
                    }
                }
    
                if (_type ==null && collection.GetType().IsGenericType)
                {
                    _type = collection.GetType().GetGenericArguments()[0];
    
                }
    
    
                if (_type == null )
                {
                    throw new ArgumentException(
                        "collection must be IEnumerable<>. Use other constructor for IEnumerable and specify type");
                }
    
                SetFields(_type);
    
                _enumerator = collection.GetEnumerator();
    
            }
    
            /// <summary>
            /// Create an IDataReader over an instance of IEnumerable.
            /// Use other constructor for IEnumerable&lt;>
            /// </summary>
            /// <param name="collection"></param>
            /// <param name="elementType"></param>
            public EnumerableDataReader(IEnumerable collection, Type elementType)
                : base(elementType)
            {
                _type = elementType;
                _enumerator = collection.GetEnumerator();
            }
    
            /// <summary>
            /// Helper method to create generic lists from anonymous type
            /// </summary>
            /// <param name="type"></param>
            /// <returns></returns>
            public static IList ToGenericList(Type type)
            {
                return (IList) Activator.CreateInstance(typeof (List<>).MakeGenericType(new[] {type}));
            }
    
            /// <summary>
            /// Return the value of the specified field.
            /// </summary>
            /// <returns>
            /// The <see cref="T:System.Object"/> which will contain the field value upon return.
            /// </returns>
            /// <param name="i">The index of the field to find. 
            /// </param><exception cref="T:System.IndexOutOfRangeException">The index passed was outside the range of 0 through <see cref="P:System.Data.IDataRecord.FieldCount"/>. 
            /// </exception><filterpriority>2</filterpriority>
            public override object GetValue(int i)
            {
                if (i < 0 || i >= Fields.Count)
                {
                    throw new IndexOutOfRangeException();
                }
    
                return Fields[i].Getter(_current);
            }
    
            /// <summary>
            /// Advances the <see cref="T:System.Data.IDataReader"/> to the next record.
            /// </summary>
            /// <returns>
            /// true if there are more rows; otherwise, false.
            /// </returns>
            /// <filterpriority>2</filterpriority>
            public override bool Read()
            {
                bool returnValue = _enumerator.MoveNext();
                _current = returnValue ? _enumerator.Current : _type.IsValueType ? Activator.CreateInstance(_type) : null;
                return returnValue;
            }
        }
    }
    
    // <copyright project="Salient.Data" file="ObjectDataReader.cs" company="Sky Sanders">
    // This source is a Public Domain Dedication.
    // Please see http://spikes.codeplex.com/ for details.   
    // Attribution is appreciated
    // </copyright> 
    // <version>1.0</version>
    
    
    using System;
    using System.Collections.Generic;
    using System.Data;
    using Salient.Reflection;
    
    namespace Salient.Data
    {
        public abstract class ObjectDataReader : IDataReader
        {
            protected bool Closed;
            protected IList<DynamicProperties.Property> Fields;
    
            protected ObjectDataReader()
            {
            }
    
            protected ObjectDataReader(Type elementType)
            {
                SetFields(elementType);
                Closed = false;
            }
    
            #region IDataReader Members
    
            public abstract object GetValue(int i);
            public abstract bool Read();
    
            #endregion
    
            #region Implementation of IDataRecord
    
            public int FieldCount
            {
                get { return Fields.Count; }
            }
    
            public virtual int GetOrdinal(string name)
            {
                for (int i = 0; i < Fields.Count; i++)
                {
                    if (Fields[i].Info.Name == name)
                    {
                        return i;
                    }
                }
    
                throw new IndexOutOfRangeException("name");
            }
    
            object IDataRecord.this[int i]
            {
                get { return GetValue(i); }
            }
    
            public virtual bool GetBoolean(int i)
            {
                return (Boolean) GetValue(i);
            }
    
           public virtual byte GetByte(int i)
            {
                return (Byte) GetValue(i);
            }
    
            public virtual char GetChar(int i)
            {
                return (Char) GetValue(i);
            }
    
            public virtual DateTime GetDateTime(int i)
            {
                return (DateTime) GetValue(i);
            }
    
            public virtual decimal GetDecimal(int i)
            {
                return (Decimal) GetValue(i);
            }
    
            public virtual double GetDouble(int i)
            {
                return (Double) GetValue(i);
            }
    
            public virtual Type GetFieldType(int i)
            {
                return Fields[i].Info.PropertyType;
            }
    
            public virtual float GetFloat(int i)
            {
                return (float) GetValue(i);
            }
    
            public virtual Guid GetGuid(int i)
            {
                return (Guid) GetValue(i);
            }
    
            public virtual short GetInt16(int i)
            {
                return (Int16) GetValue(i);
            }
    
            public virtual int GetInt32(int i)
            {
                return (Int32) GetValue(i);
            }
    
            public virtual long GetInt64(int i)
            {
                return (Int64) GetValue(i);
            }
    
            public virtual string GetString(int i)
            {
                return (string) GetValue(i);
            }
    
            public virtual bool IsDBNull(int i)
            {
                return GetValue(i) == null;
            }
    
            object IDataRecord.this[string name]
            {
                get { return GetValue(GetOrdinal(name)); }
            }
    
    
            public virtual string GetDataTypeName(int i)
            {
                return GetFieldType(i).Name;
            }
    
    
            public virtual string GetName(int i)
            {
                if (i < 0 || i >= Fields.Count)
                {
                    throw new IndexOutOfRangeException("name");
                }
                return Fields[i].Info.Name;
            }
    
            public virtual int GetValues(object[] values)
            {
                int i = 0;
                for (; i < Fields.Count; i++)
                {
                    if (values.Length <= i)
                    {
                        return i;
                    }
                    values[i] = GetValue(i);
                }
                return i;
            }
    
            public virtual IDataReader GetData(int i)
            {
                // need to think about this one
                throw new NotImplementedException();
            }
    
            public virtual long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
            {
                // need to keep track of the bytes got for each record - more work than i want to do right now
                // http://msdn.microsoft.com/en-us/library/system.data.idatarecord.getbytes.aspx
                throw new NotImplementedException();
            }
    
            public virtual long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
            {
                // need to keep track of the bytes got for each record - more work than i want to do right now
                // http://msdn.microsoft.com/en-us/library/system.data.idatarecord.getchars.aspx
                throw new NotImplementedException();
            }
    
            #endregion
    
            #region Implementation of IDataReader
    
            public virtual void Close()
            {
                Closed = true;
            }
    
    
            public virtual DataTable GetSchemaTable()
            {
                var dt = new DataTable();
                foreach (DynamicProperties.Property field in Fields)
                {
                    dt.Columns.Add(new DataColumn(field.Info.Name, field.Info.PropertyType));
                }
                return dt;
            }
    
            public virtual bool NextResult()
            {
                throw new NotImplementedException();
            }
    
    
            public virtual int Depth
            {
                get { throw new NotImplementedException(); }
            }
    
            public virtual bool IsClosed
            {
                get { return Closed; }
            }
    
            public virtual int RecordsAffected
            {
                get
                {
                    // assuming select only?
                    return -1;
                }
            }
    
            #endregion
    
            #region Implementation of IDisposable
    
            public virtual void Dispose()
            {
                Fields = null;
            }
    
            #endregion
    
            protected void SetFields(Type elementType)
            {
                Fields = DynamicProperties.CreatePropertyMethods(elementType);
            }
        }
    }
    
    // <copyright project="Salient.Reflection" file="DynamicProperties.cs" company="Sky Sanders">
    // This source is a Public Domain Dedication.
    // Please see http://spikes.codeplex.com/ for details.   
    // Attribution is appreciated
    // </copyright> 
    // <version>1.0</version>
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Reflection.Emit;
    
    namespace Salient.Reflection
    {
        /// <summary>
        /// Gets IL setters and getters for a property.
        /// 
        /// started with http://jachman.wordpress.com/2006/08/22/2000-faster-using-dynamic-method-calls/
        /// </summary>
        public static class DynamicProperties
        {
            #region Delegates
    
            public delegate object GenericGetter(object target);
    
            public delegate void GenericSetter(object target, object value);
    
            #endregion
    
            public static IList<Property> CreatePropertyMethods(Type T)
            {
                var returnValue = new List<Property>();
    
                foreach (PropertyInfo prop in T.GetProperties())
                {
                    returnValue.Add(new Property(prop));
                }
                return returnValue;
            }
    
    
            public static IList<Property> CreatePropertyMethods<T>()
            {
                var returnValue = new List<Property>();
    
                foreach (PropertyInfo prop in typeof (T).GetProperties())
                {
                    returnValue.Add(new Property(prop));
                }
                return returnValue;
            }
    
    
            /// <summary>
            /// Creates a dynamic setter for the property
            /// </summary>
            /// <param name="propertyInfo"></param>
            /// <returns></returns>
            public static GenericSetter CreateSetMethod(PropertyInfo propertyInfo)
            {
                /*
                * If there's no setter return null
                */
                MethodInfo setMethod = propertyInfo.GetSetMethod();
                if (setMethod == null)
                    return null;
    
                /*
                * Create the dynamic method
                */
                var arguments = new Type[2];
                arguments[0] = arguments[1] = typeof (object);
    
                var setter = new DynamicMethod(
                    String.Concat("_Set", propertyInfo.Name, "_"),
                    typeof (void), arguments, propertyInfo.DeclaringType);
                ILGenerator generator = setter.GetILGenerator();
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
                generator.Emit(OpCodes.Ldarg_1);
    
                if (propertyInfo.PropertyType.IsClass)
                    generator.Emit(OpCodes.Castclass, propertyInfo.PropertyType);
                else
                    generator.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
    
                generator.EmitCall(OpCodes.Callvirt, setMethod, null);
                generator.Emit(OpCodes.Ret);
    
                /*
                * Create the delegate and return it
                */
                return (GenericSetter) setter.CreateDelegate(typeof (GenericSetter));
            }
    
    
            /// <summary>
            /// Creates a dynamic getter for the property
            /// </summary>
            /// <param name="propertyInfo"></param>
            /// <returns></returns>
            public static GenericGetter CreateGetMethod(PropertyInfo propertyInfo)
            {
                /*
                * If there's no getter return null
                */
                MethodInfo getMethod = propertyInfo.GetGetMethod();
                if (getMethod == null)
                    return null;
    
                /*
                * Create the dynamic method
                */
                var arguments = new Type[1];
                arguments[0] = typeof (object);
    
                var getter = new DynamicMethod(
                    String.Concat("_Get", propertyInfo.Name, "_"),
                    typeof (object), arguments, propertyInfo.DeclaringType);
                ILGenerator generator = getter.GetILGenerator();
                generator.DeclareLocal(typeof (object));
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
                generator.EmitCall(OpCodes.Callvirt, getMethod, null);
    
                if (!propertyInfo.PropertyType.IsClass)
                    generator.Emit(OpCodes.Box, propertyInfo.PropertyType);
    
                generator.Emit(OpCodes.Ret);
    
                /*
                * Create the delegate and return it
                */
                return (GenericGetter) getter.CreateDelegate(typeof (GenericGetter));
            }
    
            #region Nested type: Property
    
            public class Property
            {
                public GenericGetter Getter;
                public PropertyInfo Info;
                public GenericSetter Setter;
    
                public Property(PropertyInfo info)
                {
                    Info = info;
                    Setter = CreateSetMethod(info);
                    Getter = CreateGetMethod(info);
                }
            }
    
            #endregion
    
            ///// <summary>
            ///// An expression based Getter getter found in comments. untested.
            ///// Q: i don't see a reciprocal setter expression?
            ///// </summary>
            ///// <typeparam name="T"></typeparam>
            ///// <param name="propName"></param>
            ///// <returns></returns>
            //public static Func<T> CreateGetPropValue<T>(string propName)
            //{
            //    var param = Expression.Parameter(typeof(object), "container");
            //    var func = Expression.Lambda(
            //    Expression.Convert(Expression.PropertyOrField(Expression.Convert(param, typeof(T)), propName), typeof(object)), param);
            //    return (Func<T>)func.Compile();
            //}
        }
    }
    
  2. ==============================

    2.당신은 마크 Gravell의 FastMember을 사용할 수 있습니다 :

    당신은 마크 Gravell의 FastMember을 사용할 수 있습니다 :

    IDataReader reader = ObjectReader.Create(myEnumerable); //all columns
    IDataReader reader = ObjectReader.Create(myEnumerable, "Id", "Name", "Description");
    

    생성 로직을 얻어 추출 할뿐 아니라 더 빨리 반사보다 속성 / 필드 값을 얻을 IL을 사용한다.

  3. ==============================

    3.그의 초기 답변 스카이 샌더스 덕분에, 그것은 큰 도움이되었다.

    그의 초기 답변 스카이 샌더스 덕분에, 그것은 큰 도움이되었다.

    나는 스카이 샌더스 'EnumerableDataReader의 일반 버전을 썼다 그러나 나는 다음과 같이 변경했다 :

    난이 도움이되기를 바랍니다 당신이 어떤 발언, 수정 또는 개선이있는 경우, 그렇게 말하십시오 :

    /// <summary>
    /// IDataReader that can be used for "reading" an IEnumerable<T> collection
    /// </summary>
    public class EnumerableDataReader<T> : IDataReader
    {
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="collection">The collection to be read</param>
        /// <param name="fields">The list of public field/properties to read from each T (in order), OR if no fields are given only one field will be available: T itself</param>
        public EnumerableDataReader(IEnumerable<T> collection, params string[] fields)
        {
            if (collection == null)
                throw new ArgumentNullException("collection");
    
            m_Enumerator = collection.GetEnumerator();
    
            if (m_Enumerator == null)
                throw new NullReferenceException("collection does not implement GetEnumerator");
    
            SetFields(fields);
        }
        private IEnumerator<T> m_Enumerator;
        private T m_Current = default(T);
        private bool m_EnumeratorState = false;
    
        private void SetFields(ICollection<string> fields)
        {
            if (fields.Count > 0)
            {
                Type type = typeof(T);
                foreach (string field in fields)
                {
                    PropertyInfo pInfo = type.GetProperty(field);
                    if (pInfo != null)
                        m_Fields.Add(new Property(pInfo));
                    else
                    {
                        FieldInfo fInfo = type.GetField(field);
                        if (fInfo != null)
                            m_Fields.Add(new Field(fInfo));
                        else
                            throw new NullReferenceException(string.Format("EnumerableDataReader<T>: Missing property or field '{0}' in Type '{1}'.", field, type.Name));
                    }
                }
            }
            else
                m_Fields.Add(new Self());
        }
        private List<BaseField> m_Fields = new List<BaseField>();
    
        #region IDisposable Members
        public void Dispose()
        {
            if (m_Enumerator != null)
            {
                m_Enumerator.Dispose();
                m_Enumerator = null;
                m_Current = default(T);
                m_EnumeratorState = false;
            }
            m_Closed = true;
        }
        #endregion
    
        #region IDataReader Members
        public void Close()
        {
            m_Closed = true;
        }
        private bool m_Closed = false;
    
        public int Depth
        {
            get { return 0; }
        }
    
        public DataTable GetSchemaTable()
        {
            var dt = new DataTable();
            foreach (BaseField field in m_Fields)
            {
                dt.Columns.Add(new DataColumn(field.Name, field.Type));
            }
            return dt;
        }
    
        public bool IsClosed
        {
            get { return m_Closed; }
        }
    
        public bool NextResult()
        {
            return false;
        }
    
        public bool Read()
        {
            if (IsClosed)
                throw new InvalidOperationException("DataReader is closed");
            m_EnumeratorState = m_Enumerator.MoveNext();
            m_Current = m_EnumeratorState ? m_Enumerator.Current : default(T);
            return m_EnumeratorState;
        }
    
        public int RecordsAffected
        {
            get { return -1; }
        }
        #endregion
    
        #region IDataRecord Members
        public int FieldCount
        {
            get { return m_Fields.Count; }
        }
    
        public Type GetFieldType(int i)
        {
            if (i < 0 || i >= m_Fields.Count)
                throw new IndexOutOfRangeException();
            return m_Fields[i].Type;
        }
    
        public string GetDataTypeName(int i)
        {
            return GetFieldType(i).Name;
        }
    
        public string GetName(int i)
        {
            if (i < 0 || i >= m_Fields.Count)
                throw new IndexOutOfRangeException();
            return m_Fields[i].Name;
        }
    
        public int GetOrdinal(string name)
        {
            for (int i = 0; i < m_Fields.Count; i++)
                if (m_Fields[i].Name == name)
                    return i;
            throw new IndexOutOfRangeException("name");
        }
    
        public bool IsDBNull(int i)
        {
            return GetValue(i) == null;
        }
    
        public object this[string name]
        {
            get { return GetValue(GetOrdinal(name)); }
        }
    
        public object this[int i]
        {
            get { return GetValue(i); }
        }
    
        public object GetValue(int i)
        {
            if (IsClosed || !m_EnumeratorState)
                throw new InvalidOperationException("DataReader is closed or has reached the end of the enumerator");
            if (i < 0 || i >= m_Fields.Count)
                throw new IndexOutOfRangeException();
            return m_Fields[i].GetValue(m_Current);
        }
    
        public int GetValues(object[] values)
        {
            int length = Math.Min(m_Fields.Count, values.Length);
            for (int i = 0; i < length; i++)
                values[i] = GetValue(i);
            return length;
        }
    
        public bool GetBoolean(int i) { return (bool)GetValue(i); }
        public byte GetByte(int i) { return (byte)GetValue(i); }
        public char GetChar(int i) { return (char)GetValue(i); }
        public DateTime GetDateTime(int i) { return (DateTime)GetValue(i); }
        public decimal GetDecimal(int i) { return (decimal)GetValue(i); }
        public double GetDouble(int i) { return (double)GetValue(i); }
        public float GetFloat(int i) { return (float)GetValue(i); }
        public Guid GetGuid(int i) {return (Guid)GetValue(i); }
        public short GetInt16(int i) { return (short)GetValue(i); }
        public int GetInt32(int i) { return (int)GetValue(i); }
        public long GetInt64(int i) { return (long)GetValue(i); }
        public string GetString(int i) { return (string)GetValue(i); }
    
        public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) { throw new NotSupportedException(); }
        public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) { throw new NotSupportedException(); }
        public IDataReader GetData(int i) { throw new NotSupportedException(); }
        #endregion
    
        #region Helper Classes
        private abstract class BaseField
        {
            public abstract Type Type { get; }
            public abstract string Name { get; }
            public abstract object GetValue(T instance);
    
            protected static void AddGetter(Type classType, string fieldName, Func<T, object> getter)
            {
                m_GetterDictionary.Add(string.Concat(classType.FullName, fieldName), getter);
            }
    
            protected static Func<T, object> GetGetter(Type classType, string fieldName)
            {
                Func<T, object> getter = null;
                if (m_GetterDictionary.TryGetValue(string.Concat(classType.FullName, fieldName), out getter))
                    return getter;
                return null;
            }
            private static Dictionary<string, Func<T, object>> m_GetterDictionary = new Dictionary<string, Func<T, object>>();
        }
    
        private class Property : BaseField
        {
            public Property(PropertyInfo info)
            {
                m_Info = info;
                m_DynamicGetter = CreateGetMethod(info);
            }
            private PropertyInfo m_Info;
            private Func<T, object> m_DynamicGetter;
    
            public override Type Type { get { return m_Info.PropertyType; } }
            public override string Name { get { return m_Info.Name; } }
    
            public override object GetValue(T instance)
            {
                //return m_Info.GetValue(instance, null); // Reflection is slow
                return m_DynamicGetter(instance);
            }
    
            // Create dynamic method for faster access instead via reflection
            private Func<T, object> CreateGetMethod(PropertyInfo propertyInfo)
            {
                Type classType = typeof(T);
                Func<T, object> dynamicGetter = GetGetter(classType, propertyInfo.Name);
                if (dynamicGetter == null)
                {
                    ParameterExpression instance = Expression.Parameter(classType);
                    MemberExpression property = Expression.Property(instance, propertyInfo);
                    UnaryExpression convert = Expression.Convert(property, typeof(object));
                    dynamicGetter = (Func<T, object>)Expression.Lambda(convert, instance).Compile();
                    AddGetter(classType, propertyInfo.Name, dynamicGetter);
                }
    
                return dynamicGetter;
            }
        }
    
        private class Field : BaseField
        {
            public Field(FieldInfo info)
            {
                m_Info = info;
                m_DynamicGetter = CreateGetMethod(info);
            }
            private FieldInfo m_Info;
            private Func<T, object> m_DynamicGetter;
    
            public override Type Type { get { return m_Info.FieldType; } }
            public override string Name { get { return m_Info.Name; } }
    
            public override object GetValue(T instance)
            {
                //return m_Info.GetValue(instance); // Reflection is slow
                return m_DynamicGetter(instance);
            }
    
            // Create dynamic method for faster access instead via reflection
            private Func<T, object> CreateGetMethod(FieldInfo fieldInfo)
            {
                Type classType = typeof(T);
                Func<T, object> dynamicGetter = GetGetter(classType, fieldInfo.Name);
                if (dynamicGetter == null)
                {
                    ParameterExpression instance = Expression.Parameter(classType);
                    MemberExpression property = Expression.Field(instance, fieldInfo);
                    UnaryExpression convert = Expression.Convert(property, typeof(object));
                    dynamicGetter = (Func<T, object>)Expression.Lambda(convert, instance).Compile();
                    AddGetter(classType, fieldInfo.Name, dynamicGetter);
                }
    
                return dynamicGetter;
            }
        }
    
        private class Self : BaseField
        {
            public Self()
            {
                m_Type = typeof(T);
            }
            private Type m_Type;
    
            public override Type Type { get { return m_Type; } }
            public override string Name { get { return string.Empty; } }
            public override object GetValue(T instance) { return instance; }
        }
        #endregion
    }
    
  4. from https://stackoverflow.com/questions/2258310/get-an-idatareader-from-a-typed-list by cc-by-sa and MIT license