使用GetType()的C#动态铸造

本文关键字:动态 GetType 使用 | 更新日期: 2023-09-27 17:58:05

我读过很多试图完成类似任务的帖子,但找不到合适的解决方案。

我正在尝试在运行时动态地转换一个对象。(我知道你们中的很多人会说这是不可能的,我实际上不确定它是否可以…)我的问题是,我在Windows Forms Application中有一个动态创建的TreeView来显示Org Chart

TreeView中的数据来自3个表:DepartmentsJobsEmployees

Tables导入为Local DataSource会将所有3个表作为DataSet对象,并将DataRow对象的模板类型转换为它所来自的表(包括作为属性的所有列)。(类似于linq-除了Oracle数据库)

我创建TreeNode对象,使用DataRow中的描述字段作为TreeNode.Text属性,然后将DataRow本身附加为TreeNode.Tag属性。这样,我可以直接在TreeNode中访问数据,只需铸造:

dsMyDataSource.DepartmentRow = 
    (dsMyDataSource.DepartmentRow)treeview1.SelectedNode.Tag;

我有一个方法,每当用户在treeview1上选择一个Node时就会运行,该方法会用一些底层对象数据填充Details窗口。到目前为止,我有一个带有switch语句的单一方法:

private doSomething()
{
    switch(treeview1.SelectedNode.Tag.GetType().Name)
    {
        case "dsMyDataSource.DepartmentRow":
            dsMyDataSource.DepartmentRow department = 
                (dsMyDataSource.DepartmentRow)treeview1.SelectedNode.Tag;
            lblDetailsTitle = department.Title;
            break;
        case "dsMyDataSource.JobRow":
            //etc...
    }
}

我想做的是为每种类型都重载方法,并去掉我的switch语句。像这样:

this.doSomething(treeview1.SelectedNode.Tag);

问题是,这会返回一个基对象(从而返回强制转换)。但我不知道在编译时用户会选择什么类型的树节点。因此,我希望能够做一些类似的事情:

this.doSomething((treeview1.SelectedNode.Tag.GetType())treeview1.SelectedNode.Tag);
private void doSomething(dsMyDataSource.DepartmentRow department)
{
    lblDetailsTitle = department.Title;
    // etc...
}
private void doSomething(dsMyDataSource.JobRow job) {..}
private void doSomething(dsMyDataSource.EmployeeRow employee) {..}

这可能吗?

使用GetType()的C#动态铸造

如果您使用一些有意义的对象,而不是直接从DataRows中工作,您可能会发现事情更干净。此外,这将允许您添加一个基类,这将使您的选角问题消失。

例如,你可以有

abstract class Selectable
{
    public string Type { get; private set; }
    public Selectable(string type) { Type = type; }
    abstract void doSomething();
}

然后为你想要选择的每件事选择一种类型

class Department : Selectable{...}, class Job : Selectable{...}

要获得基本类型,您需要在factory对象中使用一个开关。

public static class SelectableFactory
{
    public static Selectable GetFromDataRow(DataRow dr)
    {
        Selectable res = null;
        switch (dr.Type)
        {
            case "Department":
                res = new Department(dr);
                // etc ...
            }
    }
}

但是您现在有一个Selectables集合,可以使用多态性来执行操作。

除了让你的生活更轻松之外,它还将让你的代码更容易为将来必须处理它的其他人解析。它也是可扩展的,所以当你需要添加DoSomethingElse方法时,为所有内容添加它要容易得多——或者当你需要一种新类型的数据表时,你不会干扰你的UI代码。