简体   繁体   中英

C# Dynamic Casting with GetType()

I've read many posts trying to accomplish similar tasks but cannot find a proper solution to my problem.

I'm trying to dynamically cast an object at runtime. (I know a lot of you are going to say it can't be done, and I'm not actually sure if it can...) My problem is that I have a dynamically created TreeView in a Windows Forms Application to display an Org Chart .

The data in the TreeView pulls from 3 tables: Departments , Jobs , Employees .

Importing the Tables as a Local DataSource gives me all 3 Tables as DataSet Objects, and templates for DataRow objects type casted to the table it comes from (including all columns as properties). (Similar to linq - except for Oracle DB)

I create TreeNode objects, use a description field from my DataRow as the TreeNode.Text Property and then attach the DataRow itself as the TreeNode.Tag property. This way, I can access the data from directly within the TreeNode simply by casting:

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

I have a method that runs whenever the User selects a Node on treeview1 that populates a Details window with some of the underlying objects data. As of right now, I have a single method with a switch statement as such:

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

What I want to do, is to have overloaded methods for each type and get rid of my switch statements. Like so:

this.doSomething(treeview1.SelectedNode.Tag);

Problem is, this returns a base object (thus the cast). But I don't know at compile time what type of TreeNode the User will select. Thus I want to be able to do something like:

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) {..}

Is this possible?

You might find things cleaner if you use some meaningful objects rather than working directly off DataRows. In addition this will let you add a base class, which will make your casting problems go away.

So for example you could have

abstract class Selectable
{
    public string Type { get; private set; }

    public Selectable(string type) { Type = type; }

    abstract void doSomething();
}

and then a type for each thing you want to select

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

To get the base types you will need one switch in a factory object.

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

But you now have a collection of Selectables that can use polymorphism to do the action.

In addition to making your life easier it will make your code much easier to parse for anyone else that has to work on it in the future. It's also extensible, so when you need to add a DoSomethingElse method it's much easier to add for everything - or when you need a new type of datatable you don't disturb your UI code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM