使用CopyToDataTable与“new {..}”LINQ查询exception

从这个代码我可以调用bmwCars.CopyToDataTable(),如我所料。

var bmwCars = from car in dataTable.AsEnumerable() where car.Field<string>("Make").ToLower().Equals("bmw") select car; 

但是当我将代码的某些语句更改为下面的代码时,我无法调用CopyToDataTable(),为什么呢?

 var bmwCars = from car in dataTable.AsEnumerable() where car.Field<string>("Make").ToLower().Equals("bmw") select new { Make = car.Field<string>("Make"), Color = car.Field<string>("Color"), PetName = car.Field<string>("PetName") }; 

基于你使用Field<T>dataTable的对象(我假设它是Cartypes的)inheritanceDataRow 。 这是调用CopyToDataTable扩展方法所必需的。 正如所写的,但是,您正在返回不能inheritanceDataRow的匿名types的枚举。

所以,可能是你的

 select new 

应该

 select new Car 

以便您返回一个IEnumerable<Car>而不是一个匿名types的IEnumerable<>

根据您的Car类的确切结构,可能需要做一些小的合成变化。 如果Car拥有公共属性, MakeColorPetName那么它将按我的build议工作。 如果,而是Car有一个方法签名约等于的构造函数

 public Car(string make, string color, string petName) 

那么你将不得不改变LINQ语句

 var bmwCars = from car in dataTable.AsEnumerable() where car.Field<string>("Make").ToLower().Equals.("bmw") select new Car( car.Field<string>("Make"), car.Field<string>("Color"), car.Field<string>("PetName") ); 

您可以构build自己的CopyToDataTable ,它接受任何types的IEnumerable(不仅是DataRow )并返回一个新的DataTable

 // following would not compile by default // because input is not an IEnumerable<DataRow> but an anonymous type var tblResult = bmwCars.CopyToDataTable(); 

这是实施(在MSDN的帮助下):

 public class ObjectShredder<T> { private System.Reflection.FieldInfo[] _fi; private System.Reflection.PropertyInfo[] _pi; private System.Collections.Generic.Dictionary<string, int> _ordinalMap; private System.Type _type; // ObjectShredder constructor. public ObjectShredder() { _type = typeof(T); _fi = _type.GetFields(); _pi = _type.GetProperties(); _ordinalMap = new Dictionary<string, int>(); } /// <summary> /// Loads a DataTable from a sequence of objects. /// </summary> /// <param name="source">The sequence of objects to load into the DataTable.</param> /// <param name="table">The input table. The schema of the table must match that /// the type T. If the table is null, a new table is created with a schema /// created from the public properties and fields of the type T.</param> /// <param name="options">Specifies how values from the source sequence will be applied to /// existing rows in the table.</param> /// <returns>A DataTable created from the source sequence.</returns> public DataTable Shred(IEnumerable<T> source, DataTable table, LoadOption? options) { // Load the table from the scalar sequence if T is a primitive type. if (typeof(T).IsPrimitive) { return ShredPrimitive(source, table, options); } // Create a new table if the input table is null. if (table == null) { table = new DataTable(typeof(T).Name); } // Initialize the ordinal map and extend the table schema based on type T. table = ExtendTable(table, typeof(T)); // Enumerate the source sequence and load the object values into rows. table.BeginLoadData(); using (IEnumerator<T> e = source.GetEnumerator()) { while (e.MoveNext()) { if (options != null) { table.LoadDataRow(ShredObject(table, e.Current), (LoadOption)options); } else { table.LoadDataRow(ShredObject(table, e.Current), true); } } } table.EndLoadData(); // Return the table. return table; } public DataTable ShredPrimitive(IEnumerable<T> source, DataTable table, LoadOption? options) { // Create a new table if the input table is null. if (table == null) { table = new DataTable(typeof(T).Name); } if (!table.Columns.Contains("Value")) { table.Columns.Add("Value", typeof(T)); } // Enumerate the source sequence and load the scalar values into rows. table.BeginLoadData(); using (IEnumerator<T> e = source.GetEnumerator()) { Object[] values = new object[table.Columns.Count]; while (e.MoveNext()) { values[table.Columns["Value"].Ordinal] = e.Current; if (options != null) { table.LoadDataRow(values, (LoadOption)options); } else { table.LoadDataRow(values, true); } } } table.EndLoadData(); // Return the table. return table; } public object[] ShredObject(DataTable table, T instance) { FieldInfo[] fi = _fi; PropertyInfo[] pi = _pi; if (instance.GetType() != typeof(T)) { // If the instance is derived from T, extend the table schema // and get the properties and fields. ExtendTable(table, instance.GetType()); fi = instance.GetType().GetFields(); pi = instance.GetType().GetProperties(); } // Add the property and field values of the instance to an array. Object[] values = new object[table.Columns.Count]; foreach (FieldInfo f in fi) { values[_ordinalMap[f.Name]] = f.GetValue(instance); } foreach (PropertyInfo p in pi) { values[_ordinalMap[p.Name]] = p.GetValue(instance, null); } // Return the property and field values of the instance. return values; } public DataTable ExtendTable(DataTable table, Type type) { // Extend the table schema if the input table was null or if the value // in the sequence is derived from type T. foreach (FieldInfo f in type.GetFields()) { if (!_ordinalMap.ContainsKey(f.Name)) { // Add the field as a column in the table if it doesn't exist // already. DataColumn dc = table.Columns.Contains(f.Name) ? table.Columns[f.Name] : table.Columns.Add(f.Name, f.FieldType); // Add the field to the ordinal map. _ordinalMap.Add(f.Name, dc.Ordinal); } } foreach (PropertyInfo p in type.GetProperties()) { if (!_ordinalMap.ContainsKey(p.Name)) { // Add the property as a column in the table if it doesn't exist // already. DataColumn dc = table.Columns.Contains(p.Name) ? table.Columns[p.Name] : table.Columns.Add(p.Name, p.PropertyType); // Add the property to the ordinal map. _ordinalMap.Add(p.Name, dc.Ordinal); } } // Return the table. return table; } } 

现在你可以添加这些扩展:

 public static class CustomLINQtoDataSetMethods { public static DataTable CopyToDataTable<T>(this IEnumerable<T> source) { return new ObjectShredder<T>().Shred(source, null, null); } public static DataTable CopyToDataTable<T>(this IEnumerable<T> source, DataTable table, LoadOption? options) { return new ObjectShredder<T>().Shred(source, table, options); } } 

瞧! 现在CopyToDataTable与任何一种IEnumerable<T> 🙂

因为你正在返回一个新的匿名types,而不是汽车对象本身。