匿名的泛型代表表达了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
在这一点上,我不再理解正在发生什么事......我的大脑已经满了......我该怎么做才能将它用于功能性代码片段。我正在寻找做什么,以及我需要什么来包装我的头,以及所有优秀的文章,以向我解释它......任何甚至小的理解闪光都非常感谢。
该行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;
});
}
}
Dude你摇滚,我刚刚开始,并没有看到它。我非常感谢你的帮助。 – 2014-09-12 14:34:25
很好的答案,好的一切。 – 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
不错!这也是一个很好的方法..我在考虑基类,但接口更清洁!谢谢! – 2014-09-12 14:38:20
你为什么写了近你的整个问题是引用的文字? – 2014-09-12 14:28:49
我不知道,当我试图引用错误时,编辑会这样做,我回去手动修复它,因为“unquote”按钮不起作用......它只是将它留在那里..我只是想在回去之前保存它。看起来你打败了我。谢谢乔恩! – 2014-09-12 14:30:00