我们有ObservableCollection<T>
个6 ObservableCollection List<Parent>
,它们都有不同类型的子类。
我们想要做的是使用通用方法来检索具有相同类型的所有对象,换句话说,检索包含所有<T>
个孩子的列表。
这是我的源代码
类A和B是Parent的子类。
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>)
返回的列表中没有元素。我100%肯定并调试了列表,里面有元素。
使用
(List<T>)(ManagerListStack.Where(x => x._Type == typeof(T)).First().List.Cast<T>())
我收到错误&#39;无法从家长投射到A或B&#39;
答案 0 :(得分:1)
SomeListOfX as List<Y>
永远不会奏效。 Y
派生自X
这一事实并不意味着List<Y>
来自List<X>
!这两种列表类型不兼容;它们只是两种不同的类型。
List<Parent>
无法转换为List<Child>
,即使它只包含Child
类型的项,因为C#在编译时只知道静态类型,而不是运行时类型。该列表可能包含不属于Child
类型的项目。
顺便说一句,相反的情况也不起作用。因为如果您能够将List<Child>
投射到List<Parent>
,那么您可以向Parent
添加AnotherChild
或List<Parent>
类型的项目,但是基础列表仍然是List<Child>
类型,这将是f *** up!注意,转换对象不会创建新对象(即它不会转换对象),它只是告诉C#将其视为另一种类型。例如。如果你知道Child child = (Child)parent;
引用了一个孩子,你可以说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 :(得分:1)
首先,就像Olivier上面所说的那样,List<Child>
不是List<Parent>
的子类,即使Child
是Parent
的孩子。 ObservableCollection也是如此。该主题称为方差。在这里深入讨论这个问题太过分了,但您可以查看C# : Is Variance (Covariance / Contravariance) another word for Polymorphism?了解更多详情。 IEnumerable<T>
是协变的。我要改用它。如果你特别需要列表或可观察的集合,你可以在以后简单地构建它们,甚至可以将它们输入。
你想要的是一个强类型的Get函数,它从ObservableCollection&gt;返回任意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>)
}
现在,我们仍然没有您想要的行为:ObservableCollections
ObservableCollections
。事实证明,我们无法在C#的类型系统中正确地做到这一点。然而,我们可以做的是将责任从类型系统转移到程序员。我们保留ObservableCollection<IEnumerable<Parent>>
,但我们会将其填入ObservableCollections<Child>
。这是可能的,因为ObservableCollection<Child>
imlements 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”