将基数列表转换为派生类

时间:2013-11-27 15:30:42

标签: c# oop

我有一个基类

 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结果集)但是如果我转换它,它工作正常。问题是我不知道编译时的确切类型我只知道其中一个类将存在。

3 个答案:

答案 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});
}

任何人有问题或在这里看到问题?