【问题标题】:How can I convert a DataTable into a Dynamic object?如何将 DataTable 转换为 Dynamic 对象?
【发布时间】:2011-10-17 13:54:41
【问题描述】:

如何将DataTable 转换为IEnumerable<dynamicObject>

比如我想转换anyDataTable

ID | Name          DI | emaN
---------    or    ---------
 1 | x              2 | x
 2 | y              1 | y

在对象列表中

// list 1      (ex 1)             // list 2    (ex 2)
{                                 {
  { ID = 1, Name = "x" }            { DI = 2, emaN = "x" }
  { ID = 2, Name = "y" }            { DI = 1, emaN = "y" }
}                                 }

所以

list1.First().ID    // 1
list2.First().emaN  // "x"

我该怎么做?

【问题讨论】:

    标签: c# dynamic datatable ienumerable


    【解决方案1】:
    class Program
    {
        static void Main()
        {
            var dt = new DataTable();
            dt.Columns.Add("ID", typeof(int));
            dt.Columns.Add("Name", typeof(string));
            dt.Rows.Add(1, "x");
            dt.Rows.Add(2, "y");
    
            List<dynamic> dynamicDt = dt.ToDynamic();
            Console.WriteLine(dynamicDt.First().ID);
            Console.WriteLine(dynamicDt.First().Name);
        }
    }
    
    public static class DataTableExtensions
    {
        public static List<dynamic> ToDynamic(this DataTable dt)
        {
            var dynamicDt = new List<dynamic>();
            foreach (DataRow row in dt.Rows)
            {
                dynamic dyn = new ExpandoObject();
                dynamicDt.Add(dyn);
                foreach (DataColumn column in dt.Columns)
                {
                    var dic = (IDictionary<string, object>)dyn;
                    dic[column.ColumnName] = row[column];
                }
            }
            return dynamicDt;
        }
    }
    

    【讨论】:

    • 这里有点大错人! dynamicDt.Add(dyn); 行应该在内部循环之外。
    • 这个解决方案非常适合我,因为我只想从数据表绑定到数据网格。
    • 我必须在我的 .NET Core 项目中添加 NuGet Microsoft.CSharp。
    【解决方案2】:

    DynamicObject怎么样:

    public static class DataTableX
    {
        public static IEnumerable<dynamic> AsDynamicEnumerable(this DataTable table)
        {
            // Validate argument here..
    
            return table.AsEnumerable().Select(row => new DynamicRow(row));
        }
    
        private sealed class DynamicRow : DynamicObject
        {
            private readonly DataRow _row;
    
            internal DynamicRow(DataRow row) { _row = row; }
    
            // Interprets a member-access as an indexer-access on the 
            // contained DataRow.
            public override bool TryGetMember(GetMemberBinder binder, out object result)
            {
                var retVal = _row.Table.Columns.Contains(binder.Name);
                result = retVal ? _row[binder.Name] : null;
                return retVal;
            }
        }
    }
    

    如果您希望动态行可写,也可以尝试覆盖 TrySetMember

    用法

      DataTable table = ...
      var dynamicTable = table.AsDynamicEnumerable();
    
      var firstRowsNameField = dynamicTable.First().Name;
    

    【讨论】:

      【解决方案3】:

      以前的 suneelsarraf 代码仅生成具有字符串属性的运行时动态对象。 以下更新将根据 DataTable 列的数据类型生成每个属性。

      public static class DataTableExtension
      {
          /// <summary>
          ///  Convert a database data table to a runtime dynamic definied type collection (dynamic class' name as table name).
          /// </summary>
          /// <param name="dt"></param>
          /// <param name="className"></param>
          /// <returns></returns>
          public static List<dynamic> ToDynamicList(DataTable dt, string className)
          {
              return ToDynamicList(ToDictionary(dt), getNewObject(dt.Columns, className));
          }
      
          private static List<Dictionary<string, object>> ToDictionary(DataTable dt)
          {
              var columns = dt.Columns.Cast<DataColumn>();
              var Temp = dt.AsEnumerable().Select(dataRow => columns.Select(column =>
                                   new { Column = column.ColumnName, Value = dataRow[column] })
                               .ToDictionary(data => data.Column, data => data.Value)).ToList();
              return Temp.ToList();
          }
      
          private static List<dynamic> ToDynamicList(List<Dictionary<string, object>> list, Type TypeObj)
          {
              dynamic temp = new List<dynamic>();
              foreach (Dictionary<string, object> step in list)
              {
                  object Obj = Activator.CreateInstance(TypeObj);
      
                  PropertyInfo[] properties = Obj.GetType().GetProperties();
      
                  Dictionary<string, object> DictList = (Dictionary<string, object>)step;
      
                  foreach (KeyValuePair<string, object> keyValuePair in DictList)
                  {
                      foreach (PropertyInfo property in properties)
                      {
                          if (property.Name == keyValuePair.Key)
                          {
                              if (keyValuePair.Value != null && keyValuePair.Value.GetType() != typeof(System.DBNull))
                              {
                                  if (keyValuePair.Value.GetType() == typeof(System.Guid))
                                  {
                                      property.SetValue(Obj, keyValuePair.Value, null);
                                  }
                                  else
                                  {
                                      property.SetValue(Obj, keyValuePair.Value, null);
                                  }
                              }
                              break;
                          }
                      }
                  }
                  temp.Add(Obj);
              }
              return temp;
          }
      
          private static Type getNewObject(DataColumnCollection columns, string className)
          {
              AssemblyName assemblyName = new AssemblyName();
              assemblyName.Name = "YourAssembly";
              System.Reflection.Emit.AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
              ModuleBuilder module = assemblyBuilder.DefineDynamicModule("YourDynamicModule");
              TypeBuilder typeBuilder = module.DefineType(className, TypeAttributes.Public);
      
              foreach (DataColumn column in columns)
              {
                  string propertyName = column.ColumnName;
                  FieldBuilder field = typeBuilder.DefineField(propertyName, column.DataType, FieldAttributes.Public);
                  PropertyBuilder property = typeBuilder.DefineProperty(propertyName, System.Reflection.PropertyAttributes.None, column.DataType, new Type[] { column.DataType });
                  MethodAttributes GetSetAttr = MethodAttributes.Public | MethodAttributes.HideBySig;
                  MethodBuilder currGetPropMthdBldr = typeBuilder.DefineMethod("get_value", GetSetAttr, column.DataType, new Type[] { column.DataType }); // Type.EmptyTypes);
                  ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator();
                  currGetIL.Emit(OpCodes.Ldarg_0);
                  currGetIL.Emit(OpCodes.Ldfld, field);
                  currGetIL.Emit(OpCodes.Ret);
                  MethodBuilder currSetPropMthdBldr = typeBuilder.DefineMethod("set_value", GetSetAttr, null, new Type[] { column.DataType });
                  ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
                  currSetIL.Emit(OpCodes.Ldarg_0);
                  currSetIL.Emit(OpCodes.Ldarg_1);
                  currSetIL.Emit(OpCodes.Stfld, field);
                  currSetIL.Emit(OpCodes.Ret);
                  property.SetGetMethod(currGetPropMthdBldr);
                  property.SetSetMethod(currSetPropMthdBldr);
              }
              Type obj = typeBuilder.CreateType();
              return obj;
          }      
      }
      

      【讨论】:

        【解决方案4】:

        有些 ORM 可以直接从 DB 读取到 dynamic ExpandoObject。例如petapoco(并在此处阅读example

        或者您可以尝试类似的方法:

        var dt = new DataTable();
        
        var dns = new List<dynamic>();
        
        foreach (var item in dt.AsEnumerable())
        {
            // Expando objects are IDictionary<string, object>
            IDictionary<string, object> dn = new ExpandoObject();
        
            foreach (var column in dt.Columns.Cast<DataColumn>())
            {
                dn[column.ColumnName] = item[column];
            }
        
            dns.Add(dn);
        }
        
        // Now you can do something like dns[0].MyColumnName 
        // or recast to IDictionary<string, object> and do 
        // something like casted["MyColumnName"]
        

        【讨论】:

        【解决方案5】:

        你可以使用这样的扩展:

        using System;
        using System.Collections.Generic;
        using System.Data;
        using System.Dynamic;
        
        public static class DataTableExtensions
        {
            public static IEnumerable<dynamic> AsDynamicEnumerable(this DataTable table)
            {
                if (table == null)
                {
                    yield break;
                }
        
                foreach (DataRow row in table.Rows)
                {
                    IDictionary<string, object> dRow = new ExpandoObject();
        
                    foreach (DataColumn column in table.Columns)
                    {
                        var value = row[column.ColumnName];
                        dRow[column.ColumnName] = Convert.IsDBNull(value) ? null : value;
                    }
        
                    yield return dRow;
                }
            }
        }
        

        用法:

        var dataTable = GetDataTableFromSomewhere();
        var dynamicTable = dataTable.AsDynamicEnumerable();
        var firstRowIDColumn = dynamicTable.First().ID;
        var lastRowIDColumn = dynamicTable.Last()["ID"];
        

        但如果可能,我更喜欢 IDataReader 方法。

        【讨论】:

          【解决方案6】:

          试试

          var MyResult = from x in MyDataTable select new { ID = x["ID"], Name = x["Name"] }.ToList ();
          

          【讨论】:

          • 我在想一些更通用的东西。
          • 你的意思是 - 不了解这些领域?
          • 是的,完全正确。新字段可以出现或消失,也可能是完全不同的字段.....
          • 那么你最好的选择是使用像 petapoco 或 Dapper 这样的 ORM - 请参阅 xanatos 的答案
          【解决方案7】:

          将数据表转换为列表

              #region "Convert DataTable to List<dynamic>"
          
              public List<dynamic> ToDynamicList(DataTable dt)
              {
                  List<string> cols = (dt.Columns.Cast<DataColumn>()).Select(column => column.ColumnName).ToList();
                  return ToDynamicList(ToDictionary(dt), getNewObject(cols));
              }
              public List<Dictionary<string, object>> ToDictionary(DataTable dt)
              {
                  var columns = dt.Columns.Cast<DataColumn>();
                  var Temp = dt.AsEnumerable().Select(dataRow => columns.Select(column =>
                                       new { Column = column.ColumnName, Value = dataRow[column] })
                                   .ToDictionary(data => data.Column, data => data.Value)).ToList();
                  return Temp.ToList();
              }
              public List<dynamic> ToDynamicList(List<Dictionary<string, object>> list, Type TypeObj)
              {
                  dynamic temp = new List<dynamic>();
                  foreach (Dictionary<string, object> step in list)
                  {
                      object Obj = Activator.CreateInstance(TypeObj);
                      PropertyInfo[] properties = Obj.GetType().GetProperties();
                      Dictionary<string, object> DictList = (Dictionary<string, object>)step;
                      foreach (KeyValuePair<string, object> keyValuePair in DictList)
                      {
                          foreach (PropertyInfo property in properties)
                          {
                              if (property.Name == keyValuePair.Key)
                              {
                                  property.SetValue(Obj, keyValuePair.Value.ToString(), null);
                                  break;
                              }
                          }
                      }
                      temp.Add(Obj);
                  }
                  return temp;
              }       
              private Type getNewObject(List<string> list)
              {
                  AssemblyName assemblyName = new AssemblyName();
                  assemblyName.Name = "tmpAssembly";
                  AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
                  ModuleBuilder module = assemblyBuilder.DefineDynamicModule("tmpModule");
                  TypeBuilder typeBuilder = module.DefineType("WebgridRowCellCollection", TypeAttributes.Public);
                  foreach (string step in list)
                  {
                      string propertyName = step;
                      FieldBuilder field = typeBuilder.DefineField(propertyName, typeof(string), FieldAttributes.Public);
                      PropertyBuilder property = typeBuilder.DefineProperty(propertyName, System.Reflection.PropertyAttributes.None, typeof(string), new Type[] { typeof(string) });
                      MethodAttributes GetSetAttr = MethodAttributes.Public | MethodAttributes.HideBySig;
                      MethodBuilder currGetPropMthdBldr = typeBuilder.DefineMethod("get_value", GetSetAttr, typeof(string), Type.EmptyTypes);
                      ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator();
                      currGetIL.Emit(OpCodes.Ldarg_0);
                      currGetIL.Emit(OpCodes.Ldfld, field);
                      currGetIL.Emit(OpCodes.Ret);
                      MethodBuilder currSetPropMthdBldr = typeBuilder.DefineMethod("set_value", GetSetAttr, null, new Type[] { typeof(string) });
                      ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
                      currSetIL.Emit(OpCodes.Ldarg_0);
                      currSetIL.Emit(OpCodes.Ldarg_1);
                      currSetIL.Emit(OpCodes.Stfld, field);
                      currSetIL.Emit(OpCodes.Ret);
                      property.SetGetMethod(currGetPropMthdBldr);
                      property.SetSetMethod(currSetPropMthdBldr);
                  }
                  Type obj = typeBuilder.CreateType();
                  return obj;
              }
          
              #endregion
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-12-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-10-08
            • 2019-07-04
            相关资源
            最近更新 更多