Convert DataTable to Generic List in C#

后端 未结 9 1243
既然无缘
既然无缘 2020-12-01 01:28

Disclaimer: I know its asked at so many places at SO.
My query is a little different.

Coding Language: C# 3.5

I have a DataTable named cardsTable that

相关标签:
9条回答
  • 2020-12-01 02:27

    I built on top of Tomas Jansson's logic to include an "Ignore" attribute. This allows me to add other attribute's to the class being loaded without breaking the DataTable-To-Class loading itself.

    Alternatively I also considered adding a separate parameter that holds the actual column name to be read from in the DataTable. In that case instead of using "row[property.Name]" then you'd use row[attribute.Name]" or something like that for that particular property.

    public static class DataTableExtensions
    {
        [AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
        public sealed class IgnoreAttribute : Attribute { public IgnoreAttribute() { } }
    
        private static Dictionary<Type, IList<PropertyInfo>> typeDictionary = new Dictionary<Type, IList<PropertyInfo>>();
    
        public static IList<PropertyInfo> GetPropertiesForType<T>()
        {
            var type = typeof(T);
    
            if (!typeDictionary.ContainsKey(typeof(T)))
                typeDictionary.Add(type, type.GetProperties().ToList());
    
            return typeDictionary[type];
        }
    
        public static IList<T> ToList<T>(this DataTable table) where T : new()
        {
            IList<PropertyInfo> properties = GetPropertiesForType<T>();
            IList<T> result = new List<T>();
    
            foreach (var row in table.Rows)
                result.Add(CreateItemFromRow<T>((DataRow)row, properties));
    
            return result;
        }
    
        private static T CreateItemFromRow<T>(DataRow row, IList<PropertyInfo> properties) where T : new()
        {
            T item = new T();
    
            foreach (var property in properties)
            {
                // Only load those attributes NOT tagged with the Ignore Attribute
                var atr = property.GetCustomAttribute(typeof(IgnoreAttribute));
                if (atr == null)
                    property.SetValue(item, row[property.Name], null);
            }
    
            return item;
        }
    }
    
    0 讨论(0)
  • 2020-12-01 02:28

    You could actually shorten it down considerably. You can think of the Select() extension method as a type converter. The conversion could then be written as this:

    List<Cards> target = dt.AsEnumerable()
        .Select(row => new Cards
        {
            // assuming column 0's type is Nullable<long>
            CardID = row.Field<long?>(0).GetValueOrDefault(),
            CardName = String.IsNullOrEmpty(row.Field<string>(1))
                ? "not found"
                : row.Field<string>(1),
        }).ToList();
    
    0 讨论(0)
  • 2020-12-01 02:29

    Coming late but this can be useful. Can be called using:

    table.Map(); or call with a Func to filter the values.

    You can even change the mapping name between the type property and DataColumn header by setting the attributes on the property.

    [AttributeUsage(AttributeTargets.Property)]
        public class SimppleMapperAttribute: Attribute
        {
            public string HeaderName { get; set; }
        }
    
    
         public static class SimpleMapper
    {
        #region properties
        public static bool UseDeferredExecution { get; set; } = true;
        #endregion
    
    #region public_interface  
    
    
        public static IEnumerable<T> MapWhere<T>(this DataTable table, Func<T, bool> sortExpression) where T:new()
        {
            var result = table.Select().Select(row => ConvertRow<T>(row, table.Columns, typeof(T).GetProperties())).Where((t)=>sortExpression(t));
            return UseDeferredExecution ? result : result.ToArray();
        }
        public static IEnumerable<T> Map<T>(this DataTable table) where T : new()
        {
            var result = table.Select().Select(row => ConvertRow<T>(row, table.Columns, typeof(T).GetProperties()));
            return UseDeferredExecution ? result : result.ToArray();
        }
        #endregion
    
    #region implementation_details
        private static T ConvertRow<T>(DataRow row, DataColumnCollection columns, System.Reflection.PropertyInfo[] p_info) where T : new()
        {
            var instance = new T();
            foreach (var info in p_info)
            {
                if (columns.Contains(GetMappingName(info))) SetProperty(row, instance, info);             
            }
            return instance;
        }
    
        private static void SetProperty<T>(DataRow row, T instance, System.Reflection.PropertyInfo info) where T : new()
        {
            string mp_name = GetMappingName(info);
            object value = row[mp_name];
            info.SetValue(instance, value);
        }
    
        private static string GetMappingName(System.Reflection.PropertyInfo info)
        {
            SimppleMapperAttribute attribute = info.GetCustomAttributes(typeof(SimppleMapperAttribute),true).Select((o) => o as SimppleMapperAttribute).FirstOrDefault();
            return attribute == null ? info.Name : attribute.HeaderName;
        }
    #endregion
    }
    
    0 讨论(0)
提交回复
热议问题