我有一个基类
public Enum TestType{
A,
B
}
public abstract class Base{
public int ID{ get;set;}
}
和派生类
public class Derived1 : Base{
public string Prop1 {get;set;}
}
public class Derived2 : Base{
public string Prop2 {get;set;}
}
然后我有一个返回Base
的函数public IQueryable<Base> GetData(TestType type){
switch(type){
case A:
return new IQueryable<Derived1>();
case B:
return new IQueryable<Derived2>();
}
}
现在遗憾的是,我正在使用的工具之一需要实际类型,并且无法通过基类型传递。
如何将GetData的返回结果转换为实际类型,而不是Base。我正在考虑使用表达式和演员,但我无法理解。
理想情况下,GetData是一个获取数据的工厂,我不希望它有IQueryable&lt;基&GT;包含混合类的列表。我在编译时不知道类型!我想在运行时有一个从base到派生的函数,而不必检查底层类型然后进行转换(IE是一堆if语句)
编辑:添加了一些底层代码来提供帮助。现在我正在使用的控件说它无法在基础上找到属性Prop1(如果我传入返回IQueryable的GetData结果集)但是如果我转换它,它工作正常。问题是我不知道编译时的确切类型我只知道其中一个类将存在。
答案 0 :(得分:4)
LINQ有一个Cast<>
调用应该对您有用,正如文档here所述。
var myList = GetData().Cast<Derived1>();
或者,您甚至可以使用Select
扩展方法,如下所示:
var myList = GetData.Select(data => data as Derived1);
编辑:根据您最近的问题编辑,我建议您实施Factory pattern。创建一个完全基于传入的枚举值返回特定类对象的Factory。那些不同的类对象应该都实现一个特定的接口,其上有GetData()
方法,返回IQueryable
特定派生类型。您需要为您的工具执行的任何添加的逻辑也可以在该类对象上完成(并且也可以放在接口上,以便您的原始代码也可以调用它)。
这样做可以让您的代码确定在运行时动态使用哪一个,并且还允许您遵循开放 - 封闭原则。如果你想添加更多派生类型,你需要做的就是创建一个实现接口的新类对象,确保Factory知道它存在,然后让它运行。
答案 1 :(得分:1)
使用泛型并使您的GetData方法通用:
public IQueryable<T> GetData<T>() where T : Base
{
var data = ...; //object to return
return (IQueryable<T>)data;
}
我认为这最终会影响您的目标。
答案 2 :(得分:0)
我最终做了以下事情:
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});
}
任何人有问题或在这里看到问题?