Как мне использовать отражение для динамического вызова типа?

#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-интерфейсов косвенного обращения со списком, которые необходимо учитывать в этих случаях.