将列表<T> 转换为包含 T.CustomClass 属性的数据表
Convert List<T> To datatable including T.CustomClass properties
如下 this 我已成功将 List<T>
转换为 DataTable
但还有更多内容。我的 T object
基本上是一个具有属性的自定义 class,并且还引用了另一个 class。现在我还需要将 class 的属性添加到数据表中。
这是函数
public static DataTable ToDataTable<T>(this IList<T> list)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
for (int i = 0; i < properties.Count; i++)
{
PropertyDescriptor prop = properties[i];
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
}
object[] values = new object[properties.Count];
foreach (T item in list)
{
for (int i = 0; i < values.Length; i++)
values[i] = properties[i].GetValue(item) ?? DBNull.Value;
table.Rows.Add(values);
}
return table;
}
这是我对其进行自定义的努力,但无法检索 DataTable
的整行数据。由于 T 不具有 child 的属性。如何添加 child 的 T
属性或获取整行数据。
private static DataTable AddColumnsForProperties(DataTable dt, PropertyDescriptor p, ref List<PropertyDescriptor> properties)
{
if (p.PropertyType.Namespace.ToLower().StartsWith("mynamespace"))
{
var allProperties = p.GetChildProperties();
foreach (PropertyDescriptor item in allProperties)
{
if (item.PropertyType.Namespace.ToLower().StartsWith("mynamespace"))
AddColumnsForProperties(dt, item, ref properties);
else
if (!dt.Columns.Contains(item.Name))
{
dt.Columns.Add(item.Name, Nullable.GetUnderlyingType(item.PropertyType) ?? item.PropertyType);
properties.Add(item);
}
}
}
else
if (!dt.Columns.Contains(p.Name))
{
dt.Columns.Add(p.Name, Nullable.GetUnderlyingType(p.PropertyType) ?? p.PropertyType);
properties.Add(p);
}
return dt;
}
public static DataTable ToDataTable<T>(this IList<T> list)
{
DataTable table = null;
if (list != null && list.Count > 0)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
List<PropertyDescriptor> propList = new List<PropertyDescriptor>();
table = new DataTable();
foreach (PropertyDescriptor item in properties)
{
AddColumnsForProperties(table, item, ref propList);
}
object[] values = new object[propList.Count];
foreach (T item in list)
{
for (int i = 0; i < values.Length; i++)
values[i] = propList[i].GetValue(item) ?? DBNull.Value;
table.Rows.Add(values);
}
}
return table;
}
我正在开发一个仅适用于 DataTables 的自定义网格控件,因此此功能对 me.As 有很多网格需要自定义我需要具有此功能我无法创建每个 DataTable
手动。
您的函数通常在正确的轨道上,但是,从反射返回的 属性 描述符是相对于它们来自的类型的,因此 propList[i].GetValue(item)
期望 item 是子类型。即 MyParent.MyChild.Description 的 属性 描述符期望项目是 MyChild 类型,而不是 MyParent。
我对您的代码做了一些更改,以便它包含一个 属性 描述符数组,并依次使用每个描述符来检索中间属性的值。
此代码不处理 NULL 值。您可能应该更改 GetValueFromProps 以正确处理 NULL。
private static DataTable AddColumnsForProperties(string myNamespace, DataTable dt, List<PropertyDescriptor> p, ref List<PropertyDescriptor[]> properties)
{
var pLast = p.Last();
if (pLast.PropertyType.Namespace.StartsWith(myNamespace))
{
var allProperties = pLast.GetChildProperties();
foreach (PropertyDescriptor item in allProperties)
{
var newP = p.ToList();
newP.Add(item);
if (item.PropertyType.Namespace.ToLower().StartsWith(myNamespace))
AddColumnsForProperties(myNamespace, dt, newP, ref properties);
else
if (!dt.Columns.Contains(item.Name))
{
dt.Columns.Add(item.Name, Nullable.GetUnderlyingType(item.PropertyType) ?? item.PropertyType);
properties.Add(newP.ToArray());
}
}
}
else
if (!dt.Columns.Contains(pLast.Name))
{
dt.Columns.Add(pLast.Name, Nullable.GetUnderlyingType(pLast.PropertyType) ?? pLast.PropertyType);
properties.Add(p.ToArray());
}
return dt;
}
static object GetValueFromProps(PropertyDescriptor[] descriptors, object item)
{
var result = item;
foreach (var descriptor in descriptors)
{
result = descriptor.GetValue(result);
}
return result;
}
public static DataTable ToDataTable<T>(this IList<T> list)
{
DataTable table = null;
if (list != null && list.Count > 0)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
List<PropertyDescriptor[]> propList = new List<PropertyDescriptor[]>();
table = new DataTable();
foreach (PropertyDescriptor item in properties)
{
AddColumnsForProperties(typeof(T).Namespace, table, (new[] { item }).ToList(), ref propList);
}
object[] values = new object[propList.Count];
foreach (T item in list)
{
for (int i = 0; i < values.Length; i++)
values[i] = GetValueFromProps(propList[i], item) ?? DBNull.Value;
table.Rows.Add(values);
}
}
return table;
}
我定制了这个功能,所以例如相同命名空间的枚举有效,因此 child 元素具有 parent 元素的前缀。
例如。如果 class Person 的元素 car 具有 CarModell 之类的属性,则列标题将为:'Person.Car.CarModell'.
private static void AddColumnsForProperties(string myNamespace, string parentName, DataTable dt, List<PropertyDescriptor> p, ref List<PropertyDescriptor[]> properties)
{
var pLast = p.Last();
if (pLast.PropertyType.Namespace != null && pLast.PropertyType.Namespace.StartsWith(myNamespace))
{
var allProperties = pLast.GetChildProperties();
if (allProperties.Count > 0)
{
foreach (PropertyDescriptor item in allProperties)
{
var newP = p.ToList();
newP.Add(item);
string childParentName = !String.IsNullOrEmpty(parentName)
? String.Format("{0}.{1}.{2}", parentName, pLast.Name, item.Name)
: String.Format("{0}.{1}", pLast.Name, item.Name);
if (item.PropertyType.Namespace != null && item.PropertyType.Namespace.ToLower().StartsWith(myNamespace))
{
AddColumnsForProperties(myNamespace, childParentName, dt, newP, ref properties);
}
else if (!dt.Columns.Contains(childParentName))
{
dt.Columns.Add(childParentName, Nullable.GetUnderlyingType(item.PropertyType) ?? item.PropertyType);
properties.Add(newP.ToArray());
}
}
}
else if (!dt.Columns.Contains(pLast.Name))
{
dt.Columns.Add(pLast.Name, Nullable.GetUnderlyingType(pLast.PropertyType) ?? pLast.PropertyType);
properties.Add(p.ToArray());
}
}
else if (!dt.Columns.Contains(pLast.Name))
{
dt.Columns.Add(pLast.Name, Nullable.GetUnderlyingType(pLast.PropertyType) ?? pLast.PropertyType);
properties.Add(p.ToArray());
}
}
public static DataTable ToDataTable<T>(this IList<T> list)
{
DataTable table = null;
if (list != null && list.Count > 0)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
List<PropertyDescriptor[]> propList = new List<PropertyDescriptor[]>();
table = new DataTable();
foreach (PropertyDescriptor item in properties)
{
// Arrays oder Collections werden nicht in die DataTable eingefügt, da dies eher eine Art Master-Detail-Table ist.
if (IsArrayOrCollection(item.PropertyType))
{
continue;
}
AddColumnsForProperties(typeof(T).Namespace, null, table, (new[] { item }).ToList(), ref propList);
}
object[] values = new object[propList.Count];
foreach (T item in list)
{
for (int i = 0; i < values.Length; i++)
values[i] = GetValueFromProps(propList[i], item) ?? DBNull.Value;
table.Rows.Add(values);
}
}
return table;
}
如下 this 我已成功将 List<T>
转换为 DataTable
但还有更多内容。我的 T object
基本上是一个具有属性的自定义 class,并且还引用了另一个 class。现在我还需要将 class 的属性添加到数据表中。
这是函数
public static DataTable ToDataTable<T>(this IList<T> list)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
for (int i = 0; i < properties.Count; i++)
{
PropertyDescriptor prop = properties[i];
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
}
object[] values = new object[properties.Count];
foreach (T item in list)
{
for (int i = 0; i < values.Length; i++)
values[i] = properties[i].GetValue(item) ?? DBNull.Value;
table.Rows.Add(values);
}
return table;
}
这是我对其进行自定义的努力,但无法检索 DataTable
的整行数据。由于 T 不具有 child 的属性。如何添加 child 的 T
属性或获取整行数据。
private static DataTable AddColumnsForProperties(DataTable dt, PropertyDescriptor p, ref List<PropertyDescriptor> properties)
{
if (p.PropertyType.Namespace.ToLower().StartsWith("mynamespace"))
{
var allProperties = p.GetChildProperties();
foreach (PropertyDescriptor item in allProperties)
{
if (item.PropertyType.Namespace.ToLower().StartsWith("mynamespace"))
AddColumnsForProperties(dt, item, ref properties);
else
if (!dt.Columns.Contains(item.Name))
{
dt.Columns.Add(item.Name, Nullable.GetUnderlyingType(item.PropertyType) ?? item.PropertyType);
properties.Add(item);
}
}
}
else
if (!dt.Columns.Contains(p.Name))
{
dt.Columns.Add(p.Name, Nullable.GetUnderlyingType(p.PropertyType) ?? p.PropertyType);
properties.Add(p);
}
return dt;
}
public static DataTable ToDataTable<T>(this IList<T> list)
{
DataTable table = null;
if (list != null && list.Count > 0)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
List<PropertyDescriptor> propList = new List<PropertyDescriptor>();
table = new DataTable();
foreach (PropertyDescriptor item in properties)
{
AddColumnsForProperties(table, item, ref propList);
}
object[] values = new object[propList.Count];
foreach (T item in list)
{
for (int i = 0; i < values.Length; i++)
values[i] = propList[i].GetValue(item) ?? DBNull.Value;
table.Rows.Add(values);
}
}
return table;
}
我正在开发一个仅适用于 DataTables 的自定义网格控件,因此此功能对 me.As 有很多网格需要自定义我需要具有此功能我无法创建每个 DataTable
手动。
您的函数通常在正确的轨道上,但是,从反射返回的 属性 描述符是相对于它们来自的类型的,因此 propList[i].GetValue(item)
期望 item 是子类型。即 MyParent.MyChild.Description 的 属性 描述符期望项目是 MyChild 类型,而不是 MyParent。
我对您的代码做了一些更改,以便它包含一个 属性 描述符数组,并依次使用每个描述符来检索中间属性的值。
此代码不处理 NULL 值。您可能应该更改 GetValueFromProps 以正确处理 NULL。
private static DataTable AddColumnsForProperties(string myNamespace, DataTable dt, List<PropertyDescriptor> p, ref List<PropertyDescriptor[]> properties)
{
var pLast = p.Last();
if (pLast.PropertyType.Namespace.StartsWith(myNamespace))
{
var allProperties = pLast.GetChildProperties();
foreach (PropertyDescriptor item in allProperties)
{
var newP = p.ToList();
newP.Add(item);
if (item.PropertyType.Namespace.ToLower().StartsWith(myNamespace))
AddColumnsForProperties(myNamespace, dt, newP, ref properties);
else
if (!dt.Columns.Contains(item.Name))
{
dt.Columns.Add(item.Name, Nullable.GetUnderlyingType(item.PropertyType) ?? item.PropertyType);
properties.Add(newP.ToArray());
}
}
}
else
if (!dt.Columns.Contains(pLast.Name))
{
dt.Columns.Add(pLast.Name, Nullable.GetUnderlyingType(pLast.PropertyType) ?? pLast.PropertyType);
properties.Add(p.ToArray());
}
return dt;
}
static object GetValueFromProps(PropertyDescriptor[] descriptors, object item)
{
var result = item;
foreach (var descriptor in descriptors)
{
result = descriptor.GetValue(result);
}
return result;
}
public static DataTable ToDataTable<T>(this IList<T> list)
{
DataTable table = null;
if (list != null && list.Count > 0)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
List<PropertyDescriptor[]> propList = new List<PropertyDescriptor[]>();
table = new DataTable();
foreach (PropertyDescriptor item in properties)
{
AddColumnsForProperties(typeof(T).Namespace, table, (new[] { item }).ToList(), ref propList);
}
object[] values = new object[propList.Count];
foreach (T item in list)
{
for (int i = 0; i < values.Length; i++)
values[i] = GetValueFromProps(propList[i], item) ?? DBNull.Value;
table.Rows.Add(values);
}
}
return table;
}
我定制了这个功能,所以例如相同命名空间的枚举有效,因此 child 元素具有 parent 元素的前缀。 例如。如果 class Person 的元素 car 具有 CarModell 之类的属性,则列标题将为:'Person.Car.CarModell'.
private static void AddColumnsForProperties(string myNamespace, string parentName, DataTable dt, List<PropertyDescriptor> p, ref List<PropertyDescriptor[]> properties)
{
var pLast = p.Last();
if (pLast.PropertyType.Namespace != null && pLast.PropertyType.Namespace.StartsWith(myNamespace))
{
var allProperties = pLast.GetChildProperties();
if (allProperties.Count > 0)
{
foreach (PropertyDescriptor item in allProperties)
{
var newP = p.ToList();
newP.Add(item);
string childParentName = !String.IsNullOrEmpty(parentName)
? String.Format("{0}.{1}.{2}", parentName, pLast.Name, item.Name)
: String.Format("{0}.{1}", pLast.Name, item.Name);
if (item.PropertyType.Namespace != null && item.PropertyType.Namespace.ToLower().StartsWith(myNamespace))
{
AddColumnsForProperties(myNamespace, childParentName, dt, newP, ref properties);
}
else if (!dt.Columns.Contains(childParentName))
{
dt.Columns.Add(childParentName, Nullable.GetUnderlyingType(item.PropertyType) ?? item.PropertyType);
properties.Add(newP.ToArray());
}
}
}
else if (!dt.Columns.Contains(pLast.Name))
{
dt.Columns.Add(pLast.Name, Nullable.GetUnderlyingType(pLast.PropertyType) ?? pLast.PropertyType);
properties.Add(p.ToArray());
}
}
else if (!dt.Columns.Contains(pLast.Name))
{
dt.Columns.Add(pLast.Name, Nullable.GetUnderlyingType(pLast.PropertyType) ?? pLast.PropertyType);
properties.Add(p.ToArray());
}
}
public static DataTable ToDataTable<T>(this IList<T> list)
{
DataTable table = null;
if (list != null && list.Count > 0)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
List<PropertyDescriptor[]> propList = new List<PropertyDescriptor[]>();
table = new DataTable();
foreach (PropertyDescriptor item in properties)
{
// Arrays oder Collections werden nicht in die DataTable eingefügt, da dies eher eine Art Master-Detail-Table ist.
if (IsArrayOrCollection(item.PropertyType))
{
continue;
}
AddColumnsForProperties(typeof(T).Namespace, null, table, (new[] { item }).ToList(), ref propList);
}
object[] values = new object[propList.Count];
foreach (T item in list)
{
for (int i = 0; i < values.Length; i++)
values[i] = GetValueFromProps(propList[i], item) ?? DBNull.Value;
table.Rows.Add(values);
}
}
return table;
}