0

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.

dbarnes
  • 1,803
  • 3
  • 17
  • 31

3 Answers3

4

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.

Corey Adler
  • 15,897
  • 18
  • 66
  • 80
  • any number, but for now I have 4 and each IQueryable has the same type I was thinking about doing a OfType and checking for null and continuing on but I don't think that is the best option. – dbarnes Nov 27 '13 at 15:37
  • @dbarnes If you don't know that type in compile time then how'll you statically type it to a variable? – Sriram Sakthivel Nov 27 '13 at 15:38
  • I Do know it at compile time but it returns IQueryable and I need to convert it to its underlying type. – dbarnes Nov 27 '13 at 15:44
  • 1
    The second example using `Select` works similar to the built in `OfType` extension: `var myList = GetData.OfType()`, the built in method will filter out objects which aren't of the type specified - not sure if that is desired. – Anthony Nov 27 '13 at 15:45
  • +1. Just to mention that there exists an alternative; use "ConvertAll" instead of "Select" (http://stackoverflow.com/questions/1571819/difference-between-select-and-convertall-in-c-sharp) – Xavier Egea Aug 03 '15 at 09:58
1

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.

sjkm
  • 3,887
  • 2
  • 25
  • 43
  • I Do not know the type at compile time :/ – dbarnes Nov 27 '13 at 15:50
  • which type you don't know at compile time? The type you want to convert to? – sjkm Nov 27 '13 at 15:53
  • I want to go from Base to it's underlying derived, I'm looking into creating an expression that does this using reflection on the underlying type I just was thinking there may be a better way. – dbarnes Nov 27 '13 at 15:54
  • ok, but somewhere you must know the type at least when you want to to something with it (the concret derived type) and exactly there you can use the generic? – sjkm Nov 27 '13 at 15:57
0

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?

dbarnes
  • 1,803
  • 3
  • 17
  • 31
  • 2
    Your readability in this case is not good, not to mention that this is going to a royal pain to maintain, especially if someone besides you ends up having to do it... – Corey Adler Nov 27 '13 at 17:07
  • @Freerider I didn't know the type at compile time so this was the only route, if you do know the type then by all means do use the other answers. – dbarnes Aug 03 '15 at 11:30