C# 具有协方差的DataGridView?

C# 具有协方差的DataGridView?,c#,datagridview,covariance,C#,Datagridview,Covariance,我有下面这样的代码(我已经对其进行了泛化和简化,以表示手头的问题)。该代码可以工作,即它接受DataGridView.DataSource并使用EPPlus将数据输出到Excel文件。我想我的问题是关于协方差以及如何使用它 因此,您可以看到它根据在数据源中找到的类型构建newList。然后再往下一点,它使用此类型特有的属性,someClassObject.Name、.Address和.Phone添加数据 我的问题是大约有75个不同的类可以通过DataGridView参数传入。尽管给定的DataG

我有下面这样的代码(我已经对其进行了泛化和简化,以表示手头的问题)。该代码可以工作,即它接受
DataGridView.DataSource
并使用
EPPlus
将数据输出到Excel文件。我想我的问题是关于协方差以及如何使用它

因此,您可以看到它根据在
数据源中找到的类型构建
newList
。然后再往下一点,它使用此类型特有的属性,
someClassObject.Name、.Address和.Phone添加数据

我的问题是大约有75个不同的类可以通过
DataGridView
参数传入。尽管给定的
DataGridView.DataSource
中的所有对象都属于同一个类,但每个类都有自己独特的属性(即不一定是名称、地址、电话)

我可以有一个基于
type.FullName
giantswitch语句,然后每个语句都有自己的for循环来将属性值分配给单元格。这会起作用,但会非常麻烦。有更好的方法吗

public void openExcelReport(ref DataGridView dataGridView, bool bolSave = false, bool bolOpen = true, string pageTitle = "EXPORTED DATA")
{
    // put dataGridView.DataSource into a List
    object firstItem = null;
    var myDataSource = dataGridView.DataSource;
    var myList = ((System.Windows.Forms.BindingSource)dataGridView.DataSource).List;
    firstItem = ((System.Collections.IList)myList)[0]; 
    var type = firstItem.GetType();

    Type PROJECT1_TYPE = typeof(Project1.SomeClass);
    Type PROJECT2_TYPE = typeof(Project2.SomeOtherClass); // many more of these

    dynamic newList = null;

    if (type.FullName.Equals(PROJECT1_TYPE.FullName))
    {
        newList = new List<Project1.SomeClass>();
        foreach (Project1.SomeClass someClassObject in myList)
        {
            newList.Add(someClassObject);
        }
    }

    ExcelPackage package = new ExcelPackage();
    using ((package)) // use EPPlus
    {
        // Create the worksheet
        ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Worksheet 1");

        // Load the datatable into the sheet, starting from cell A1. Print the column names on row 1

        System.Data.DataTable dataTable = new System.Data.DataTable();

        dataTable.Columns.Add("Id");
        dataTable.Columns.Add("FirstColumn", typeof(string));
        dataTable.Columns.Add("SecondColumn", typeof(string));
        dataTable.Columns.Add("ThirdColumn", typeof(string));

        dataTable.Columns[0].AutoIncrement = true;

        var column_id = 0;
        foreach (Project1.SomeClass someClassObject in "FirstColumn")
        {
            DataRow dataRow = dataTable.NewRow();

            dataRow["FirstColumn"] = someClassObject.Name;
            dataRow["SecondColumn"] = someClassObject.Address;
            dataRow["ThirdColumn"] = someClassObject.Phone

            dataTable.Rows.Add(dataRow);

            column_id += 1;

        }

        // worksheet is now populated, so save Excel File     
        ...

}
public void openExcelReport(ref DataGridView DataGridView,bool bolSave=false,bool bolOpen=true,string pageTitle=“导出数据”)
{
//将dataGridView.DataSource放入列表中
对象firstItem=null;
var myDataSource=dataGridView.DataSource;
var myList=((System.Windows.Forms.BindingSource)dataGridView.DataSource).List;
firstItem=((System.Collections.IList)myList)[0];
var type=firstItem.GetType();
类型PROJECT1\u Type=typeof(PROJECT1.SomeClass);
Type PROJECT2_Type=typeof(PROJECT2.SomeOtherClass);//更多
动态newList=null;
if(type.FullName.Equals(PROJECT1_type.FullName))
{
newList=新列表();
foreach(myList中的Project1.SomeClass SomeClass对象)
{
添加(someClassObject);
}
}
ExcelPackage=新的ExcelPackage();
使用((包))//使用ePlus
{
//创建工作表
Excel工作表=package.Workbook.Worksheets.Add(“工作表1”);
//从单元格A1开始,将数据表加载到工作表中。在第1行打印列名
System.Data.DataTable DataTable=新的System.Data.DataTable();
dataTable.Columns.Add(“Id”);
Add(“FirstColumn”,typeof(string));
Add(“SecondColumn”,typeof(string));
Add(“ThirdColumn”,typeof(string));
dataTable.Columns[0]。自动增量=true;
var列_id=0;
foreach(Project1.SomeClass someClassObject位于“第一列”)
{
DataRow DataRow=dataTable.NewRow();
dataRow[“FirstColumn”]=someClassObject.Name;
dataRow[“SecondColumn”]=someClassObject.Address;
dataRow[“ThirdColumn”]=someClassObject.Phone
dataTable.Rows.Add(dataRow);
列_id+=1;
}
//工作表现在已填充,请保存Excel文件
...
}

您可以使用公共接口将其移出类实现,以强制执行,而不是在此函数中创建
DataRow
,例如:

public interface DataRowConvertable
{
    DataRow GetDataRow();
}

public class SomeClass : DataRowConvertable
{
    public SomeClass() { }
    public SomeClass(string name, string address, string phone)
    {
        Name = name;
        Address = address;
        Phone = phone;
    }

    public string Name { get; set; }
    public string Address { get; set; }
    public string Phone { get; set; }

    public DataRow GetDataRow()
    {
        DataRow row = GetDataTable().NewRow();
        row["Name"] = this.Name;
        row["Address"] = this.Address;
        row["Phone"] = this.Phone;
        return row;
    }

    public static DataTable GetDataTable()
    {
        DataTable table = new DataTable("SomeClassTable");
        table.Columns.Add("Name", typeof(string));
        table.Columns.Add("Address", typeof(string));
        table.Columns.Add("Phone", typeof(string));
        return table;
    }
}
您可以更进一步,但这会给您一个很好的选择和开始的地方。您可以将
GetDataTable
函数保留为公共函数,也可以将其用于创建表实例,或者将其设置为私有函数,仅在内部使用。我会选择前者,并在函数中使用它来初始化表您甚至可以去掉
static
修饰符并将其添加到界面中,但我更喜欢在这个实例中静态使用它,因为它不依赖于类的实例和所涉及的数据,只依赖于结构

无论哪种方式,您都可以将上面的代码更改为如下所示:

ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Worksheet 1");
System.Data.DataTable dataTable = Project1.SomeClass.GetDataTable();

foreach (Project1.SomeClass someClassObject in myList)
{
    dataTable.Rows.Add(someClassObject.GetDataRow());
}
如果您需要一个递增的
id
列,您可以轻松地将其添加到
GetDataTable
/
GetDataRow
函数中,并像上面一样更新它们


这只是一个简单的例子,它很可能会被清理和优化一些,但它仍然传达了这个想法。希望它能帮助您解决一些问题。

您可以使用一个公共接口将它移到类实现中,而不是在这个函数中创建
DataRow
,例如:

public interface DataRowConvertable
{
    DataRow GetDataRow();
}

public class SomeClass : DataRowConvertable
{
    public SomeClass() { }
    public SomeClass(string name, string address, string phone)
    {
        Name = name;
        Address = address;
        Phone = phone;
    }

    public string Name { get; set; }
    public string Address { get; set; }
    public string Phone { get; set; }

    public DataRow GetDataRow()
    {
        DataRow row = GetDataTable().NewRow();
        row["Name"] = this.Name;
        row["Address"] = this.Address;
        row["Phone"] = this.Phone;
        return row;
    }

    public static DataTable GetDataTable()
    {
        DataTable table = new DataTable("SomeClassTable");
        table.Columns.Add("Name", typeof(string));
        table.Columns.Add("Address", typeof(string));
        table.Columns.Add("Phone", typeof(string));
        return table;
    }
}
您可以更进一步,但这会给您一个很好的选择和开始的地方。您可以将
GetDataTable
函数保留为公共函数,也可以将其用于创建表实例,或者将其设置为私有函数,仅在内部使用。我会选择前者,并在函数中使用它来初始化表您甚至可以去掉
static
修饰符并将其添加到界面中,但我更喜欢在这个实例中静态使用它,因为它不依赖于类的实例和所涉及的数据,只依赖于结构

无论哪种方式,您都可以将上面的代码更改为如下所示:

ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Worksheet 1");
System.Data.DataTable dataTable = Project1.SomeClass.GetDataTable();

foreach (Project1.SomeClass someClassObject in myList)
{
    dataTable.Rows.Add(someClassObject.GetDataRow());
}
如果您需要一个递增的
id
列,您可以轻松地将其添加到
GetDataTable
/
GetDataRow
函数中,并像上面一样更新它们


这只是一个简单的例子,它很可能会被清理和优化一些,但它仍然传达了这个想法。希望它能帮助您解决一些问题。

对于您正在传递的类,您能否修改它们以实现一个具有
GetDataRow()
(或类似内容)的接口函数,这样您就可以在类实现本身中拥有该代码,然后在这里您只需执行
dataTable.Rows.Add(someClassObject.GetDataRow())
。并完成它。这将使您不需要