匿名的泛型代表表达了lambda表达式... Ithink

问题描述:

所以我试图用三种不同的方式来做一些事情,只是略微超出了我的理解边缘。让我解释一下我在做什么 然后我会详细解释我对 的理解。匿名的泛型代表表达了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

该行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

由于三个使用.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