dbarnes
dbarnes

Reputation: 1833

Converting List of base to derived class

I have one base class

 public Enum TestType{
   A,
   B
 }

public abstract class Base{
    public int ID{ get;set;}
}

and a derived class

public class Derived1 : Base{
   public string Prop1 {get;set;}
}
public class Derived2 : Base{
   public string Prop2 {get;set;}
}

then I have a function that returns Base

public IQueryable<Base> GetData(TestType type){
   switch(type){
      case A:
        return new IQueryable<Derived1>();
      case B:
        return new IQueryable<Derived2>();
    }

}

Now sadly one of the tools I'm working with needs the actual type and cannot get away with passing in the base type.

How do I convert the return result from GetData to it's actual type and not Base. I was thinking using expressions and cast but I cannot figure it out.

Idealy the GetData is a factory that get's the data, I don't expect there to be IQueryable< Base> to contain a list of mixed classes. I DO NOT KNOW THE TYPE AT COMPILE TIME! I'd like to have a function from base to derived at run time without having to check the underlying type then doing a cast( IE a bunch of if statements)

EDIT: added some underlying code to help. Now the control I'm using says it can't find property Prop1 on base( if I pass in the result set of GetData that returns IQueryable) but if I convert it, it works fine. the problem is I do not know the exact type at compile time I just know that one of the classes will be there.

Upvotes: 0

Views: 1267

Answers (3)

dbarnes
dbarnes

Reputation: 1833

I ended up doing the following:

var ds = GetData(...);
if(ds.Any()){
    var m = typeof(Queryable).GetMethod("Cast",BindingFlags.Static | BindingFlags.Public, null,new[] { typeof(IQueryable<Base>) }, null).MakeGenericMethod(ds.First().GetType());
    var r = m.Invoke(ds, new[] {ds});
}

Anyone have a problem or for see problems here?

Upvotes: 0

Corey Adler
Corey Adler

Reputation: 16137

LINQ has a Cast<> call that should work for you, as documented here.

var myList = GetData().Cast<Derived1>();

Or, you could even use the Select extension method as follows:

var myList = GetData.Select(data => data as Derived1);

EDIT: Based on your most recent question edit, I would recommend that you implement a Factory pattern. Create a Factory that will return a specific class object based entirely on the enum value that gets passed in. Those different class objects should all implement a specific interface that has the GetData() method on it that returns an IQueryable of that specific derived type. Any added logic that you'd need to do for your tool could also be done on that class object as well (and be put on the interface as well so that your original code can call it too).

Doing it this way allows your code to determine which one to use dynamically at run time, and also allows you to follow the Open-Closed Principle. If you ever add more derived types, all you need to do is create a new class object that implements the interface, make sure that the Factory knows that it exists, and then just let it run.

Upvotes: 4

sjkm
sjkm

Reputation: 3937

Use generics and make your GetData method generic:

public IQueryable<T> GetData<T>() where T : Base
{
    var data = ...; //object to return
    return (IQueryable<T>)data;
}

I think this does what you are trying to do in the end.

Upvotes: 1

Related Questions