Reputation: 1833
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
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
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
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