2014-09-12 77 views
0

所以我試圖用三種不同的方式來做一些事情,只是略微超出了我的理解邊緣。讓我解釋一下我在做什麼 然後我會詳細解釋我對 的理解。匿名的泛型代表表達了lambda表達式... Ithink

我有幾個詞典,其中包含我需要生成 報告的對象。他們都是

ConcurrentDictionary< Int64, List< EarningsReportCV>> 

其中盈利CV是隻包含 特性(自定義視圖模型)的自定義對象。

我有三個這樣的字典......並且初始化他們的代碼是 幾乎相同,他們每個都只包含一個不同的類CV。

下面是一個例子:

private void BuildDictForAllEarn(List<EarningsReportCV> list, ConcurrentDictionary<Int64, List<EarningsReportCV>> theDict) 
{ 
    foreach (EarningsReportCV cv in list) 
    { 
     if (theDict.ContainsKey(Convert.ToInt64(cv.Ssn))) 
     { 
      //append in list already in Dict - EWB 
      theDict[ Convert.ToInt64(cv.Ssn) ].Add(cv); 
     } 
     else 
     { 
      //insert inital list into the Dict - EWB 
      List<EarningsReportCV> cvList = new List<EarningsReportCV>(); 
      cvList.Add(cv); 
      theDict.AddOrUpdate(Convert.ToInt64(cv.Ssn), cvList, (foundkey, oldvalue => cvList); 
     } 
    } 
} 

所有三本字典是有方向性的斷絃<T>.Ssn

而不必只用類型的CV 變化的複製和粘貼代碼,我想使一個通用的方法。爲此,我需要在一個匿名委託中傳遞 ,這允許我一般採用類型T中傳遞的 並獲取它的.Ssn屬性作爲關鍵字。

我一派,思想和閱讀並走到這一步......

通用:

private void BuildDict<T>(List<T> list, ConcurrentDictionary<Int64, List<T>> theDict, Func<T, string> getIndexFunc) 

{ 
    foreach (T cv in list) 
    { 
     if (theDict.ContainsKey(Convert.ToInt64(getIndexFunc(cv)))) 
     { 
      //append in list already in Dict - EWB 
      theDict[ Convert.ToInt64(getIndexFunc(cv)) ].Add(cv); 
     } 
     else 
     { 
      //insert inital list into the Dict - EWB 
      List<EarningsReportCV> cvList = new List<EarningsReportCV>(); 
      cvList.Add(cv); 
      theDict.AddOrUpdate(Convert.ToInt64(getIndexFunc(cv)), cvList, (foundkey, oldvalue) => cvList); 
     } 
    } 
} 

我稱之爲正是如此

private void BuildDictForAllEarnLAMBDA(List<EarningsReportCV> list, ConcurrentDictionary<Int64, List<EarningsReportCV>> theDict) 
{ 
    BuildDict<EarningsReportCV>(list, theDict, (T) => { return T.Ssn; });// fix this lambda as paramether stuff...- EWB 
} 

認爲我得到的一切,除了有3r d參數,其中I 想要作爲lambda傳遞以查找的.Ssn屬性通用類型<T>

當我編譯它,我得到這些錯誤..

錯誤43參數1:無法從 'T' 轉換成 'EFRGPayroll3G.CV.EarningsReportCV' C:\用戶\ Brown.Ericw \文檔\ Visual Studio中 \項目\ WindowsService1 \ WindowsService1 \ BLL \ RazorReportRenderBLL.cs 406 33 WindowsService1
錯誤45參數2:不能從 'System.Collections.Generic.List<EFRGPayroll3G.CV.EarningsReportCV>''System.Func<long,System.Collections.Generic.List<T>>'ç轉換:\用戶\ Brown.Ericw \文檔\ Visual Studi ø 2013 \項目\ WindowsService1 \ WindowsService1 \ BLL \ RazorReportRenderBLL.cs 407 81 WindowsService1
錯誤46參數3:無法從 'lambda表達式' 轉換到 'System.Func<long,System.Collections.Generic.List<T>,System.Collections.Generic.List<T>>' C:\用戶\ Brown.Ericw \文檔\ Visual Studio中 2013 \項目\ WindowsService1 \ WindowsService1 \ BLL \ RazorReportRenderBLL。CS 407 89 WindowsService1
誤差44,用於 'System.Collections.Concurrent.ConcurrentDictionary<long,System.Collections.Generic.List<T>>.AddOrUpdate(long, System.Func<long,System.Collections.Generic.List<T>> System.Func<long,System.Collections.Generic.List<T>, System.Collections.Generic.List<T>>)' 最好重載的方法匹配具有一些無效參數C:\用戶\ Brown.Ericw \文件\視覺 工作室 2013 \項目\ WindowsService1 \ WindowsService1 \ BLL \ RazorReportRenderBLL.cs 407 21 WindowsService1
誤差42,用於 'System.Collections.Generic.List<EFRGPayroll3G.CV.EarningsReportCV>.Add(EFRGPayroll3G.CV.EarningsReportCV)' 最好重載的方法匹配具有一些無效參數C:\用戶\ Brown.Ericw \文檔\ Visual Studio中 \項目\ WindowsService1 \ WindowsService1 \ BLL \ RazorReportRenderBLL.cs 406 21 WindowsService1

在這一點上,我不再理解正在發生什麼事......我的大腦已經滿了......我該怎麼做才能將它用於功能性代碼片段。我正在尋找做什麼,以及我需要什麼來包裝我的頭,以及所有優秀的文章,以向我解釋它......任何甚至小的理解閃光都非常感謝。

+1

你爲什麼寫了近你的整個問題是引用的文字? – 2014-09-12 14:28:49

+0

我不知道,當我試圖引用錯誤時,編輯會這樣做,我回去手動修復它,因爲「unquote」按鈕不起作用......它只是將它留在那裏..我只是想在回去之前保存它。看起來你打敗了我。謝謝喬恩! – 2014-09-12 14:30:00

回答

2

該行List<EarningsReportCV> cvList = new List<EarningsReportCV>();應該使用T而不是EarningsReportCV

你讓你的函數是通用的,但忘記將舊的具體類的這兩個實例改爲泛型類型。該方法在該更改後編譯。

話雖如此,有幾個問題你可能應該改變你的功能。

首先,它似乎試圖安全地從多個線程中調用,但事實並非如此。在您檢查是否存在密鑰後,可以在另一個線索中添加或刪除密鑰,從而導致物品被丟棄在地板上。

您的程序的前提是添加一個項目,如果它不存在,並更新它,如果是。那正好什麼AddOrUpdate被設計來做原子。你應該簡單地調用一次,而不是你在做什麼。它甚至使代碼更簡單。

private void BuildDict<T>(List<T> list, 
    ConcurrentDictionary<long, List<T>> theDict, 
    Func<T, string> getIndexFunc) 
{ 
    foreach (T cv in list) 
    { 
     theDict.AddOrUpdate(Convert.ToInt64(getIndexFunc(cv)), 
      key => new List<T>() { cv }, 
      (foundkey, oldvalue) => 
      { 
       oldvalue.Add(cv); 
       return oldvalue; 
      }); 
    } 
} 

還有一些其他更改可以使您改進代碼。由於您只反覆使用list並且絕不會做其他任何事情,因此您可以將該參數設置爲IEnumerable,使其成爲除列表之外的任何類型的序列。

如果你的程序被設計爲從多個線程訪問和操縱theDict,那麼很可能內部列表不應該是列表,而應該是一個專用於從多個線程訪問的集合,例如a ConcurrentBag

由於您正在接受的代表確實需要long而不是string,這實際上應該接受,而不是接受string並嘗試將其轉換。

這給我們:

private void BuildDict<T>(IEnumerable<T> sequence, 
    ConcurrentDictionary<long, ConcurrentBag<T>> theDict, 
    Func<T, long> keySelector) 
{ 
    foreach (T cv in sequence) 
    { 
     theDict.AddOrUpdate(keySelector(cv), 
      key => new ConcurrentBag<T>() { cv }, 
      (foundkey, oldvalue) => 
      { 
       oldvalue.Add(cv); 
       return oldvalue; 
      }); 
    } 
} 
+0

Dude你搖滾,我剛剛開始,並沒有看到它。我非常感謝你的幫助。 – 2014-09-12 14:34:25

+0

很好的答案,好的一切。 – 2014-09-12 14:57:28

1

由於三個使用.Ssn你不需要訪問Func<>。你需要告訴他們的方法都具有SSN:

interface IHasSsn 
    { 
     string Ssn; 
    } 

private void BuildDict<T>(List<T> list, 
          ConcurrentDictionary<Int64, List<T>> theDict) 
    where T : IHasSsn 
{ 
    foreach (T cv in list) 
    { 
     long ssn = Convert.ToInt64(cv.Ssn); 
     if (theDict.ContainsKey(ssn)) 
     { 
      theDict[ssn].Add(cv); 
     } 
     else 
     { 
      var cvList = new List<T>(); 
      cvList.Add(cv); 
      theDict.AddOrUpdate(ssn, cvList, (foundkey, oldvalue => cvList); 
     } 
    } 
} 

並確保每個ReportCV實現IHasSsn

+0

不錯!這也是一個很好的方法..我在考慮基類,但接口更清潔!謝謝! – 2014-09-12 14:38:20