2013-01-16 17 views
1

我需要一個包含一些對象的列表來計算。我可以在列表<T>中使用匿名類型而不是輔助類嗎?

我當前的代碼看起來像這樣

private class HelperClass 
{ 
    public DateTime TheDate {get;set;} 
    public TimeSpan TheDuration {get;set;} 
    public bool Enabled {get;set;} 
} 

private TimeSpan TheMethod() 
{ 
    // create entries for every date 
    var items = new List<HelperClass>(); 
    foreach(DateTime d in GetAllDatesOrdered()) 
    { 
     items.Add(new HelperClass { TheDate = d, Enabled = GetEnabled(d), }); 
    } 

    // calculate the duration for every entry 
    for (int i = 0; i < items.Count; i++) 
    { 
     var item = items[i]; 
     if (i == items.Count -1) // the last one 
      item.TheDuration = DateTime.Now - item.TheDate; 
     else 
      item.TheDuration = items[i+1].TheDate - item.TheDate; 
    } 

    // calculate the total duration and return the result 
    var result = TimeSpan.Zero; 
    foreach(var item in items.Where(x => x.Enabled)) 
     result = result.Add(item.TheDuration); 
    return result; 
} 

現在我發現它有點難看只是介紹了我的計算(助手類)類型。 我的第一種方法是像我通常這樣使用Tuple<DateTime, TimeSpan, bool>,但由於我需要在創建實例後修改TimeSpan,所以我不能使用Tuple,因爲Tuple.ItemX是隻讀的。

我想到了一個匿名的類型,但我無法弄清楚如何初始化我的名單

var item1 = new { TheDate = DateTime.Now, 
        TheDuration = TimeSpan.Zero, Enabled = true }; 

var items = new List<?>(); // How to declare this ??? 
items.Add(item1); 
+0

匿名類型的字段是['readonly'](http://msdn.microsoft.com/en-us/library/bb397696.aspx) - 它們只能在施工過程中設置 - 所以不會比'Tuple'的想法。 –

+0

btw,'result.Add'不會改變'result',但會返回一個新的'TimeSpan'。因此,當前的實現總是返回0. –

+0

你是對的,我的真實世界的代碼做到了這一點。忘記在示例代碼中包含這些內容。 –

回答

2

使用投影看起來像是我前進的方式 - 但您可以通過「自由縮放」您的集合與其自身,然後偏移1來計算持續時間。然後,您可以做整個方法在一個查詢:

// Materialize the result to avoid computing possibly different sequences 
var allDatesAndNow = GetDatesOrdered().Concat(new[] { DateTime.Now }) 
             .ToList(); 

return allDatesNow.Zip(allDatesNow.Skip(1), 
         (x, y) => new { Enabled = GetEnabled(x), 
             Duration = y - x }) 
        .Where(x => x.Enabled) 
        .Aggregate(TimeSpan.Zero, (t, pair) => t + pair.Duration); 

Zip呼籲對了每一日期,其後續的一個,每對值轉換成持續時間和啓用的標誌。 Where調用過濾出禁用的對。調用Aggregate會將結果對的持續時間相加。

+0

是不是'Concat'的參數IEnumerable?你可能是指新的[] {DateTime.Now}'或類似的。 –

+0

@mikez:哎呀,是的 - 會解決的。 –

+0

+1,因爲您還修復了始終返回0的原始錯誤。 –

2

可以與LINQ做到這一點,如:

var itemsWithoutDuration = GetAllDatesOrdered() 
    .Select(d => new { TheDate = d, Enabled = GetEnabled(d) }) 
    .ToList(); 
var items = itemsWithoutDuration 
    .Select((it, k) => new { TheDate = it.d, Enabled = it.Enabled, 
     TheDuration = (k == (itemsWithoutDuration.Count - 1) ? DateTime.Now : itemsWithoutDuration[k+1].TheDate) - it.TheDate }) 
    .ToList(); 

但由點Tuple是更可讀和更簡潔!

+0

但是OP需要另一個屬性,TheDuration',稍後計算 –

+0

@mikez:謝謝,我錯過了。我添加了一個默認值,以便匿名類有一個可以稍後更新的佔位符。 – DocMax

+2

但匿名類型是隻讀的。 –

相關問題