#c# #.net #generics #reflection #datatable
#c# #.net #общие сведения #отражение #datatable
Вопрос:
У меня есть DataGrid, и мне нужно преобразовать его в DataTable. Проблема в том, что мне нужно иметь возможность динамически получать тип моего источника данных. Источник данных сетки имеет тип ‘Observable’, который является классом, который у меня есть в моем проекте, но моя задача — иметь возможность динамически создавать DataTable без необходимости указывать тип только с использованием источника данных. Как я могу сгенерировать метод, который я могу использовать для размещения, <T>
не получая ошибку » ‘mytype’ является переменной, но используется как тип» .
Type mytype = Grid_Job.DataSource.GetType();
DataTable dt = CreateDataTable<mytype>((IEnumerable<mytype>)Grid_Job.DataSource);
public static DataTable CreateDataTable<T>(IEnumerable<T> list)
{
Type type = typeof(T);
var properties = type.GetProperties();
DataTable dataTable = new DataTable();
foreach (PropertyInfo info in properties)
{
dataTable.Columns.Add(new DataColumn(info.Name, Nullable.GetUnderlyingType(info.PropertyType) ?? info.PropertyType));
}
foreach (T entity in list)
{
object[] values = new object[properties.Length];
for (int i = 0; i < properties.Length; i )
{
values[i] = properties[i].GetValue(entity);
}
dataTable.Rows.Add(values);
}
return dataTable;
}
Мой наблюдаемый класс
public class Observable
{
public int JobNo { get; set; }
public string JobName { get; set; }
public string JobDescription { get; set; }
public string Job_Type { get; set; }
public string Job_Status { get; set; }
}
Комментарии:
1. Можете ли вы показать свой
Observable
класс. Реализует ли он `IEnumerable<T>’?2. да, когда я использую IEnumerable<Observable >, код работает просто отлично и введите mytype = Grid_Job.DataSource . GetType(); возвращает «Наблюдаемый» правильно, но я не могу использовать его в коде.
3. Какие фактические типы могут быть
DataSource
здесь? это важно, потому что существует множество способов сделать это и несколько особенно важных абстракций, которые необходимо использовать в некоторых случаях. Итак: если вы это сделалиGrid_Job.DataSource.GetType()
: что это?4. итак, я использовал строку s = mytype . toString(); и строка s возвращается буквально «System. Коллекции. Объектная модель. ObservableCollection’ 1 [ERP_UI.Job.Observable]» где ERP_UI — это имя моего проекта, а Job — папка, содержащая класс Observable
5. и MyType . Имя возвращает «Наблюдаемый»
Ответ №1:
По сути, вам нужно отказаться от обобщений и думать в терминах коллекции во время выполнения — обнаружение самого типа элемента. Например:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Reflection;
static class P
{
static object GetData()
=> new ObservableCollection<Observable>
{
new Observable { JobName = "abc", JobNo = 123 },
new Observable { JobName = "def", JobNo = 456 },
new Observable { JobName = "ghi", JobNo = 789 },
};
static void Main()
{
// note that we don't know *anything* about the data source here
object dataSource = GetData();
DataTable dt = CreateDataTable((IEnumerable)dataSource);
foreach (DataColumn col in dt.Columns)
{
Console.Write(col.ColumnName);
Console.Write("t");
}
Console.WriteLine();
foreach (DataRow row in dt.Rows)
{
foreach (DataColumn col in dt.Columns)
{
Console.Write(row[col]);
Console.Write("t");
}
Console.WriteLine();
}
}
public static DataTable CreateDataTable(IEnumerable list)
{
Type type = GetElementType(list.GetType());
var properties = type.GetProperties();
DataTable dataTable = new DataTable();
foreach (PropertyInfo info in properties)
{
dataTable.Columns.Add(new DataColumn(info.Name, Nullable.GetUnderlyingType(info.PropertyType) ?? info.PropertyType));
}
object[] values = new object[properties.Length];
foreach (object entity in list)
{
for (int i = 0; i < properties.Length; i )
{
values[i] = properties[i].GetValue(entity);
}
dataTable.Rows.Add(values);
}
return dataTable;
}
static Type GetElementType(Type type)
{
foreach (Type interfaceType in type.GetInterfaces())
{
if (interfaceType.IsGenericType amp;amp;
interfaceType.GetGenericTypeDefinition()
== typeof(IList<>))
{
return type.GetGenericArguments()[0];
}
}
return null;
}
}
public class Observable
{
public int JobNo { get; set; }
public string JobName { get; set; }
public string JobDescription { get; set; }
public string Job_Type { get; set; }
public string Job_Status { get; set; }
}
Обратите внимание, что в некоторых случаях вы должны предпочесть TypeDescriptor
модель отражению, поскольку это позволяет определять свойства во время выполнения; это область ниши и, вероятно, к вам не относится, но об этом важно знать. В качестве примера, это то, как DataTable
itself выбирает предоставление свойств, которые у него есть, как обнаруживаемые во время выполнения, инструментам общего назначения. Существует также несколько API-интерфейсов косвенного обращения со списком, которые необходимо учитывать в этих случаях.