[英]In converting List<T> to DataTable add select properties from class
我正在尝试将列表转换为数据表。 我已经完成了基本大纲,但被困在一个部分。 我试图只从 class 中获取一些属性。
public static DataTable ToDataTable<T>(this IList<T> data)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
table.Columns.Add("type", typeof(string));
table.Columns.Add("id", typeof(Int32));
table.Columns.Add("name", typeof(string));
table.Columns.Add("city", typeof(string));
foreach (T item in data)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
{
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
}
table.Rows.Add(row);
}
return table;
}
问题是当它到达第二个属性时,它会抛出一个错误,指出列“unincludedCol”不属于表。
我该如何解决这个问题?
如果您只需要type、id、name 和 city ,您可以将它们添加到字符串列表中:
List<string> columnNames = new List<string>
{
"type","id","name","city"
};
或者从dataTable
中提取它们,例如:
List<string> columnNames = new List<string>();
foreach(DataColumn column in dataTable.Columns)
{
columnNames.Add(column.ColumnName);
}
并在循环中检查columnNames
是否包含prop.Name
,例如:
foreach (T item in data)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
{
if(!columnNames.Contains(prop.Name))
continue;
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
}
table.Rows.Add(row);
}
注意:代替if(.columnNames.Contains(prop.Name))
,您可以使用 .Any .Any()
和Equals
方法来忽略大小写:
if (!columnNames.Any(c => c.Equals(prop.Name, StringComparison.OrdinalIgnoreCase)))
continue;
我希望你觉得这有帮助。
我相信使用一个属性是属性会更通用。 还允许您分配属性名称别名。
属性
[AttributeUsage(AttributeTargets.Property)]
public class UseAsTableColumn : Attribute
{
public string Alias { get; private set; }
public UseAsTableColumn(string columnAlias = null)
{
this.Alias = columnAlias;
}
}
助手 - 更改了您的方法(使用属性名称作为列名称)
public static class Helper
{
public static string GetDisplayName(PropertyInfo pi)
{
var uatAttrib = pi.GetCustomAttribute(typeof(UseAsTableColumn), true) as UseAsTableColumn;
return uatAttrib.Alias == null ? pi.Name : uatAttrib.Alias;
}
public static DataTable ToDataTable<T>(this IList<T> data)
{
var mappableAttrirbs = typeof(T).GetProperties().Where(x => x.GetCustomAttributes(typeof(UseAsTableColumn), true).FirstOrDefault() != null);
DataTable table = new DataTable();
foreach (var property in mappableAttrirbs)
{
table.Columns.Add(GetDisplayName(property), property.PropertyType);
}
foreach (T item in data)
{
DataRow row = table.NewRow();
foreach (var property in mappableAttrirbs)
{
row[GetDisplayName(property)] = property.GetValue(item) ?? DBNull.Value;
}
table.Rows.Add(row);
}
return table;
}
}
数据 Model(标记要序列化的属性)
public class DataModel
{
[UseAsTableColumn]
public string Type { get; set; }
[UseAsTableColumn]
public int Id { get; set; }
[UseAsTableColumn("name")]
public string Name { get; set; }
[UseAsTableColumn]
public string City { get; set; }
public string _InternalValue { get; private set; }
}
赛跑者
public class Program
{
static void Main(string[] args)
{
List<DataModel> data = new List<DataModel>()
{
new DataModel() { Type="Magic", Id= 1, Name = "foo", City = "bar" },
new DataModel() { Type="Magic", Id= 2, Name = "foo1", City = "bar1" }
};
Helper.ToDataTable(data);
Console.ReadKey();
}
}
我可以建议一个已经很好接受的答案的额外要点吗?
在您的通用方法中,您似乎依赖于属性“type”、“id”、“name”和“city”的存在。 这样的事情不应该放任不管。
为保证class <T> 将具有这四个属性,请考虑在 ToDataTable 方法中约束 T ,如下所示:
public static DataTable ToDataTable<T>(this IList<T> data) where T : IMyConstraint
{}
...其中IMyConstraint被声明为...
interface IMyConstraint
{
string type { get; }
int id { get; }
string name { get; }
string city { get; }
}
这使您的通用方法对于任何实现 IMyConstraint 的 class <T> 都是安全的:
class SomeClass : IMyConstraint
如果(正如您的代码所暗示的那样)您想要在 DataTable 中使用的四个属性是已知的,您仍然可以迭代名称:
private static DataTable ToDataTable<T>(IEnumerable<T> data) where T : IMyConstraint
{
DataTable table = new DataTable();
Type type = typeof(T);
// "If" you already know the names of the properties you want...
string[] names = new string[] { "type", "id", "name", "city" };
foreach (var name in names) // Add columns
{
table.Columns.Add(name, type.GetProperty(name).PropertyType);
}
foreach (var item in data) // Add rows
{
object[] values =
names
.Select(name => type.GetProperty(name).GetValue(item))
.ToArray();
table.Rows.Add(values);
}
return table;
}
...或者可能更清洁,只需迭代 IMyConstraints 接口:
private static DataTable ToDataTableAlt<T>(IEnumerable<T> data) where T : IMyConstraint
{
DataTable table = new DataTable();
PropertyInfo[] propertyInfos = typeof(IMyConstraint).GetProperties();
foreach (var propertyInfo in propertyInfos) // Add columns
{
table.Columns.Add(propertyInfo.Name, propertyInfo.PropertyType);
}
foreach (var item in data) // Add rows
{
object[] values =
propertyInfos
.Select(propertyInfo => propertyInfo.GetValue(item))
.ToArray();
table.Rows.Add(values);
}
return table;
}
从 GitHub克隆或下载此工作示例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.