【问题标题】:How do I use reflection to dynamically call a type?如何使用反射来动态调用类型?
【发布时间】:2020-11-05 08:21:41
【问题描述】:

我有一个 DataGrid,我需要将它转换为一个 DataTable。问题是我需要能够动态获取我的 DataSource 的类型。网格 DataSource 的类型为“Observable”,这是我项目中的一个类,但我的任务是能够动态创建 DataTable,而无需仅使用 DataSource 指定类型。如何生成一个可以用来放置在<T> 中的方法,而不会出现错误“'mytype' is a variable but is used like a type”。

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;
        }

我的 Observable 类是

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; }
}

【问题讨论】:

  • 你能展示你的Observable类吗?它是否实现了`IEnumerable'?
  • 是的,当我使用 IEnumerable 代码工作得很好,键入 mytype = Grid_Job.DataSource.GetType();正确返回“Observable”,但我不能在代码中使用它。
  • DataSource 中可能存在的 实际 类型是什么?这很重要,因为有多种方法可以做到这一点,并且在某些情况下需要使用一些特别相关的抽象。所以:如果你做了Grid_Job.DataSource.GetType():那是什么?
  • 所以我使用了 string s = mytype.ToString();并且字符串 s 按字面意思返回 "System.Collections.ObjectModel.ObservableCollection' 1 [ERP_UI.Job.Observable]" 其中 ERP_UI 是我的项目的名称,Job 是包含 Observable 类的文件夹
  • 和 myType.Name 返回“Observable”

标签: c# .net generics reflection datatable


【解决方案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 &&
                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 本身就是这样选择将其在运行时可发现的属性公开给通用工具的。在这些情况下,还需要考虑一些列表间接 API。

【讨论】:

    猜你喜欢
    • 2014-07-02
    • 1970-01-01
    • 2018-12-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多