Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return dynamic return types in methods? C#

I am having a problem with the return type of a method.

The method returns a linq object which at present returns type tblAppointment. This method is shown below:

public tblAppointment GetAppointment(int id)
{
    var singleAppointment = (from a in dc.tblAppointments
                                                    where a.appID == id
                                                    select a).SingleOrDefault();
    return singleAppointment;

}

The problem is that tblAppointment is abstract and has many sub types that inherit it. When I try and return an object that is of Type "appointmentTypeA" and call the .GetType() method on it, it gives me the correct sub type, but when i try and access the properties it only allows me to access the parent properties. If i take the object and cast it to a new object of the subtype then it works and lets me access everything i need but it seems messy.

var viewSingleAppointment = appointmentRepos.GetAppointment(appointmentId);

Debug.Write(viewSingleAppointment.GetType()); //returns type i want

if (viewSingleAppointment is tblSingleBirthAppointment)
{
    tblSingleBirthAppointment myApp = (tblSingleBirthAppointment)viewSingleAppointment; //need to do this to access TypeA properties for some reason

}

Edit: I have got this working but I need to use a select statement for each appointment (about 20) and cast them to the appropriate type and retreive the properties and im not sure how to refactor this as it will be used on a few pages we are doing.

like image 544
Andrew Avatar asked Sep 21 '09 15:09

Andrew


People also ask

Can we use dynamic as return type in C#?

Yes there are ways by which you can deliver different objects on run time and dynamic is one of those solution. Today, we will understand how to use dynamic keyword to return a whole different object on runtime. You can even change the return type based on your input.

What is dynamic data type?

In C# 4.0, a new type is introduced that is known as a dynamic type. It is used to avoid the compile-time type checking. The compiler does not check the type of the dynamic type variable at compile time, instead of this, the compiler gets the type at the run time.


1 Answers

You're solving the wrong problem. If you have a superclass A, with subclasses B, C, etc., that all have similar functionality, you want to do the following:

  1. Make A an interface that B, C, etc. implement. Code that works with B or C instances does by working through the interface provided by A. If you can define a common set of operations that work on all the types, then this is all you need to do.

  2. If you can't define a common set of operations, e.g. you have code similar to:

    A foo = GetA();
    if(foo is B) {
        B bFoo = (B) foo;
        // Do something with foo as a B
    } else if(foo is C) {
        C cFoo = (C) foo;
        // Do something with foo as a C
    } ...
    

    Or even this (which is basically the same thing, just using extra information to emulate what the type system already provides for you):

    A foo = GetA();
    MyEnum enumeratedValue = foo.GetEnumeratedValue();
    switch(enumeratedValue) {
        case MyEnum.B:
            B bFoo = (B) foo;
            // Do something with foo as a B
            break;
        case MyEnum.C:
            C cFoo = (C) foo;
            // Do something with foo as a C
            break;
    }
    

    Then what you really want is to do something like:

    A foo = GetA();
    foo.DoSomething();
    

    Where each subclass would implement the corresponding branch of the switch statement. This is actually better in several ways:

    • It uses less overall code.
    • Since the implementations of the cases live in the various implementation classes, no casting is necessary; they can access all the member variables directly.
    • Since you're not building a big switch/case block separate from the actual B and C implementations, you don't run any risk of accidentally forgetting to add a corresponding case if add a new subclass. If you leave the DoSomething() method out of a subclass of A, you will get a compile-time error.

Edit: In response to your comment:

If your DoSomething() routine needs to operate on a Form or other GUI element, just pass that element into the method. For example:

public class B : A {
    public void DoSomething(MyForm form) {
        form.MyLabel.Text = "I'm a B object!";
    }
}

public class C : A {
    public void DoSomething(MyForm form) {
        form.MyLabel.Text = "I'm a C object!";
    }
}

// elsewhere, in a method of MyForm:

A foo = GetA();
foo.DoSomething(this);

Alternatively, an even better idea might be to turn your B and C classes into custom controls, since they seem to encapsulate display logic.

like image 140
Daniel Pryden Avatar answered Sep 29 '22 14:09

Daniel Pryden