2014-04-06 65 views
2

我们有一个ObservableCollection<T>共6 ObservableCollection List<Parent>,它们都具有不同类型的子类。将父类转换为子类

我们想要做的是使用通用方法来检索所有具有相同类型的对象,换句话说,检索包含所有<T>孩子的列表。

这里是我的源代码

类A和B是父母的子类。

ObservableCollection<ManagerTemplate> ManagerListStack = new ObservableCollection<ManagerTemplate>(ManagerTemplates); 


class ManagerTemplate 
{ 
public Type _Type { get; set; } 
public ObservableCollection<Parents> parentList {get;set;} 
} 

internal static List<ManagerTemplate> ManagerTemplates = new List<ManagerTemplate>() 
{ 
    new ManagerTemplate{ List= new ObservableCollection<Parent>(),Type=typeof(A)}, 
    new ManagerTemplate{ List= new ObservableCollection<Parent>(),Type=typeof(B)} 
}; 

public static List<T> Get<T>() where T : Parent 
{ 
    /*(ManagerListStack.Where(x => x._Type == typeof(T)).First().List.Cast<T>()).ToList(); -- TRY 1*/ 
    /*(List<T>)(ManagerListStack.Where(x => x._Type == typeof(T)).First().List.Cast<T>())* -- TRY 2*/ 
    return (ManagerListStack.Where(x => x._Type == typeof(T)).First().List.Cast<T>()).ToList(); 
} 

使用

(ManagerListStack.Where(x => x._Type == typeof(T)).First().List as List<T>) 

返回的列表中没有elements.I我100%肯定,并已调试的列表,里面有元素。

使用

(List<T>)(ManagerListStack.Where(x => x._Type == typeof(T)).First().List.Cast<T>()) 

我得到一个错误 '无法从父转换为A或B'

+0

我理解正确的话那ManagerTemplate将始终保持一个Obeservable单一类型的父类的集合? – Martijn

+0

是的,正确的。每个ManagerTemplate内部都将是一个包含相同类型对象的ObserableCollection。 – user2920222

+1

你的问题是什么?你似乎已经有了一个解决方案。 –

回答

1

SomeListOfX as List<Y>不会有任何效果。 Y派生自X这一事实并不意味着List<Y>派生自List<X>!这两种列表类型不兼容;它们只是两种不同的类型。

A List<Parent>不能转换为List<Child>,即使它仅包含类型为Child的项目,因为C#在编译时只知道静态类型,而不知道运行时类型。该列表可能包含不是Child类型的项目。

顺便说一句,反之亦然。因为如果你能够将List<Child>投射到List<Parent>,那么你可以在List<Parent>中添加一个ParentAnotherChild类型的项目,但由于底层列表仍然是List<Child>类型,所以这样做会发生!注意,转换对象不会创建新对象(即不会转换对象),它只是告诉C#将它视为另一种类型。例如。如果您知道parent引用了孩子,则可以说Child child = (Child)parent;


(List<T>)(ManagerListStack.Where(x => x._Type == typeof(T)).First().List.Cast<T>()) 

Cast<T>产生一个IEnumerable<T>,你不能施放IEnumerable<T>List<T>!一个枚举不是一个列表。


什么工作是

List<Y> listOfY = listOfX.Cast<Y>().ToList(); 

如果X可以转换为Y


你的第三个(取消注释)例如,在Get<T>作品:

return ManagerListStack 
    .Where(x => x._Type == typeof(T)) 
    .First().List 
    .Cast<T>() 
    .ToList(); 
1

首先,像奥利维尔上面说的,一个List<Child>不是List<Parent>一个子类,即使ChildParent一个孩子。 ObservableCollection也是一样。这个主题被称为方差。在这里深入讨论它太远了,但你可以看看C# : Is Variance (Covariance/Contravariance) another word for Polymorphism?了解更多细节。 IEnumerable<T>是协变的。我将转向那个。如果你特别需要列表或可观察的集合,你可以简单地构造它们,或者甚至喂它们。

你想要的是一个强类型的Get函数,它从ObservableCollection> U中返回任意的IEnumerable,其中U是T的孩子让我们看看,如果我们可以写一个签名:

IEnumerable<U> Get<U, T>(ObservableCollection<IEnumerable<T>> source) where U : T

这就是我们想要的最抽象的版本,但我们实际上并不需要它是通用的:我们已经知道编译时的基类型。为了方便阅读,我们可以让它更加具体:

IEnumerable<U> Get<U>(ObservableCollection<IEnumerable<Parent>> source) where U : Parent

现在,让我们认真填写函数体:

IEnumerable<U> Get<U>(ObservableCollection<IEnumerable<Parent>> source) where U : Parent { 
    return source.First(inner => inner is IEnumerable<U>) 
} 

哇,这是其实很简单!

这不是你想要的api。如果我们把一切融合在一起,我们得到

ObservableCollection<IEnumerable<Parent>> ManagerListStack = new ObservableCollection<IEnumerable<Parent>>(ManagerTemplates); 


internal static List<IEnumerable<Parent>> ManagerTemplates = new List<IEnumerable<Parent>> 
{ 
    new IEnumerable<ChildA>(){}, 
    new IEnumerable<ChildB>(){}, 
}; 

IEnumerable<U> Get<U>() where U : Parent { 
    return ManagerListStack.First(inner => inner is IEnumerable<U>) 
} 

现在为止,我们还没有你想要的行为:的ObservableCollectionsObservableCollections。事实证明,我们无法在C#的类型系统中正确执行此操作。然而,我们可以做的是将责任从类型系统转移到程序员。我们保留ObservableCollection<IEnumerable<Parent>>,但我们填写ObservableCollections<Child>。这是可能的,因为ObservableCollection<Child>实体IEnumerable<Child>IEnumerable<Child>IEnumerable<Parent>的子类型。

ObservableCollection<IEnumerable<Parent>> ManagerListStack = new ObservableCollection<IEnumerable<Parent>>(ManagerTemplates); 


internal static List<IEnumerable<Parent>> ManagerTemplates = new List<IEnumerable<Parent>> 
{ 
    new ObservableCollection<ChildA>(){}, 
    new ObservableCollection<ChildB>(){}, 
}; 

ObservableCollection<U> Get<U>() where U : Parent { 
    return (ObservableCollection<U>)ManagerListStack.First(inner => inner is ObservableCollection<U>) 
} 

我们使用铸铁作为逃生舱口要解决这个问题并没有提供一个共同的变体的ObservableCollection库的限制(这似乎是不可能的,无论如何,所以不要责怪他们吧)

完整的程序我在LinqPad用于测试:

void Main() 
{ 
    new Test().Get<ChildA>().First().Talk(); 
} 

class Test { 

     internal List<IEnumerable<Parent>> ManagerTemplates; 
     private ObservableCollection<IEnumerable<Parent>> ManagerListStack; 

     public Test() { 
     this.ManagerTemplates = new List<IEnumerable<Parent>> 
     { 
      new ObservableCollection<ChildA>(){ new ChildA()}, 
      new ObservableCollection<ChildB>(){ new ChildB()}, 
     }; 

     this.ManagerListStack = new ObservableCollection<IEnumerable<Parent>>(this.ManagerTemplates); 
     } 

     public ObservableCollection<U> Get<U>() where U : Parent { 
      return (ObservableCollection<U>)ManagerListStack.FirstOrDefault(inner => inner is ObservableCollection<U>); 
     } 
} 

abstract class Parent { 
    abstract public void Talk(); 
} 

class ChildA : Parent { 
    public override void Talk(){ 
     Console.WriteLine("I'm an A"); 
    } 

} 

class ChildB : Parent { 
public override void Talk(){ 
     Console.WriteLine("I'm a B"); 
    } 
} 

正如预期的那样,它打印“我是一个A”