2014-04-06 123 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」