具有匿名代表的泛型表达了一个lambdas..我想
本文关键字:我想 lambdas 一个 泛型 | 更新日期: 2023-09-27 18:21:43
所以我正在尝试做一些稍微超出我边缘的事情理解。。。以三种不同的方式。让我解释一下我是什么尝试这样做,那么我会得到我缺乏的细节理解。
我有几个字典,其中包含我需要生成的对象报告。他们都是
ConcurrentDictionary< Int64, List< EarningsReportCV>>
其中收入简历是仅包含以下内容的自定义对象属性(自定义视图模型(。
我有三本这样的词典...初始化它们的代码是几乎相同,它们每个都包含不同的简历类。
下面是一个例子:
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 参数之外的所有东西,我想要作为 lambda 传入以查找 .的 Ssn 属性泛型类型 <T>
.
当我编译它时,我得到这些错误。
错误 43 参数 1:无法从"T"转换为 'EFRGPayroll3G.CV.EarningsReportCV' C:''Users''Brown.Ericw''Documents''Visual 演播室 2013''Projects''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>>'
C:''Users''Brown.Ericw''Documents''Visual 演播室 2013''Projects''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:''Users''Brown.Ericw''Documents''Visual 演播室 2013''Projects''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:''Users''Brown.Ericw''Documents''Visual 演播室 2013''Projects''WindowsService1''WindowsService1''BLL''RazorReportRenderBLL.cs 407 21 WindowsService1
错误 42 最佳重载方法匹配'System.Collections.Generic.List<EFRGPayroll3G.CV.EarningsReportCV>.Add(EFRGPayroll3G.CV.EarningsReportCV)'
有一些无效的参数 C:''Users''Brown.Ericw''Documents''Visual 演播室 2013''Projects''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
,则内部列表很可能不应该是列表,而应该是设计为从多个线程(例如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;
});
}
}
由于这三个都使用.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 );
}
}
}
并确保每个报告简历都实现了IHasSsn