2012-11-11 34 views
3

我有一個名爲ItemChange<T>類,看起來像這樣:我如何連接兩個不同的列表<T>哪裏都有相同的基類?

public class ItemChange<T> where T : MyBase 
{ 
    public DateTime When { get; set; } 
    public string Who { get; set; } 
    public T NewState; 
    public T OldState; 
} 

正如你可以看到它存儲的對象(NewStateOldState)的兩個副本。我用它來比較字段的變化。

我現在試圖讓這幾個不同類型的牛逼名單的工作,在那裏我得到跨越多個對象的更改的列表,然後連接成一個陣列是這樣的(注:兩個Object1Object2MyBase得出:

public IEnumerable<ItemChange<T>> GetChangeHistory<T>(int numberOfChanges) where T : MyBase 
{ 
    IEnumerable<ItemChange<Object1>> obj1Changes= GetChanges<Object1>(); 
    IEnumerable<ItemChange<Object2>> obj1Changes= GetChanges<Object2>(); 
    return obj1Changes.Concat(obj2Changes).OrderByDescending(r => r.When).Take(numberofChanges); 
} 

正如你可以看到我需要連接多個類型的變化,但後來我想抓住最新的變動數(由numberOfChanges定義)

對我怎麼能拿下面的工作有什麼建議正如Concat系列給我的ompiler錯誤(我假設我必須以某種特殊的方式來實現此功能)。

有沒有辦法做到這一點?

+0

請參閱[「堆棧溢出不允許標題在標題中」](http://meta.stackexchange.com/questions/19190/should-questions-include-tags-in-their-titles/130208#130208) 。 –

+0

您是否嘗試投射到'(IEnumerable >)obj2Changes'? – Alex

+0

也許是這樣的? 'return obj1Changes.Cast >()。Concat(obj2Changes.Cast >())。OrderByDescending(r => r.When).Take(numberofChanges);' –

回答

4

我建議您加入基類爲ItemChange<T>,調用ItemChangeItemChange可以聲明When屬性。然後,將列表內容轉換爲基礎ItemChange以進行concat和order by變得非常容易。

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace brosell 
{ 

public class MyBase 
{ 

} 

public class ItemChange 
{ 
    public DateTime When { get; set; } 

} 

public class ItemChange<T>: ItemChange where T : MyBase 
{ 
    public string Who { get; set; } 
    public T NewState; 
    public T OldState; 
} 

public class Sub1: MyBase 
{ 

} 

public class Sub2: MyBase 
{ 

} 

    public class HelloWorld 
    { 
    public static void Main(string[] args) 
    { 
     List<ItemChange<Sub1>> listOfSub1 = new List<ItemChange<Sub1>>(); 
     List<ItemChange<Sub2>> listOfSub2 = new List<ItemChange<Sub2>>(); 

     var concated = listOfSub1.Cast<ItemChange>().Concat(listOfSub2.Cast<ItemChange>()); 

     var filtered = concated.OrderByDescending(ic => ic.When).Take(10); 

     Console.WriteLine("{0}", filtered.Count()); 
     } 
    } 
} 
+0

當然現在的挑戰是數字瞭解你的結果過濾列表實際包含的內容!我會考慮重構架構以更好地表示業務邏輯。例如,爲什麼ItemChange 甚至需要知道改變了什麼? – brosell

1

這個怎麼樣?我不確定,因爲我現在無法測試它。

public IEnumerable<ItemChange<T>> GetChangeHistory<T>(int numberOfChanges) where T : MyBase 
{ 
    IEnumerable<ItemChange<MyBase>> obj1Changes = GetChanges<Object1>().Select(i => new ItemChange<MyBase>(){ When = i.When, Who = i.Who, NewState = i.NewState, OldState = i.OldState }); 
    IEnumerable<ItemChange<MyBase>> obj1Changes = GetChanges<Object2>().Select(i => new ItemChange<MyBase>(){ When = i.When, Who = i.Who, NewState = i.NewState, OldState = i.OldState }); 
    return obj1Changes.Concat(obj2Changes).OrderByDescending(r => r.When).Take(numberofChanges); 
} 

它創造的ItemChange<MyBase>ItemChange<Object1>ItemChange<Object2>一個新的實例。

根據您的使用情況,您可能希望將.ToList()添加到Linq的末尾以提高性能。

1

由於ItemChange<Object1>ItemChange<Object2>之間沒有轉換,因此您嘗試執行的操作並不安全,並且肯定沒有轉換爲某些任意的ItemChange<T>。你可以嘗試做的最好的是ItemChange<MyBase>但類不是在C#協變的,所以這是無效的:

ItemChange<MyBase> change = new ItemChange<Object1>(); 

因此,您無法施放IEnumerable<ItemChange<Object1>>IEnumerable<ItemChange<Object2>>

但是,如果你的ItemChange<T>類中創建一個接口,那麼你可以安全地做到這一點:

public interface IItemChange<out T> where T : MyBase 
{ 
    DateTime When { get; set; } 
    string Who { get; set; } 
    T NewState { get; } 
    T OldState { get; } 
} 

public class ItemChange<T> : IItemChange<T> where T : MyBase 
{ 
    public DateTime When { get; set; } 
    public string Who { get; set; } 
    public T NewState { get; set; } 
    public T OldState { get; set; } 
} 

然後,您可以您GetChangesGetChangeHistory方法更改爲:

private static IEnumerable<IItemChange<T>> GetChanges<T>() where T : MyBase { ... } 

public static IEnumerable<IItemChange<MyBase>> GetChangeHistory(int numberOfChanges) 
{ 
    IEnumerable<IItemChange<MyBase>> obj1Changes = GetChanges<Object1>(); 
    IEnumerable<IItemChange<MyBase>> obj2Changes = GetChanges<Object2>(); 
    return obj1Changes.Concat(obj2Changes).OrderByDescending(r => r.When).Take(numberOfChanges); 
} 
0

如果你定義的接口IReadableItemChange<out T>裏面露出T類型的只讀屬性,而不是類型的字段,如果ItemChange<T>實施IReadableItemChange<T>,那麼這兩個ItemChange<Derived1>ItemChange<Derived2>將實施IReadableItemChange<MyBase>(並且,順便說一句,IReadableItemChange<baseType>爲任何baseType使得Derived1:baseTypeDerived2:baseType)。 ItemChange<T>可能有一個構造函數,它接受IReadableItemChange<T>並從中複製數據。

相關問題