繁体   English   中英

匿名代表的泛型表达了一个lambdas…Ithink

[英]Generics wtih anonymous Delegates expressed a lambdas… 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参数外,其他所有东西我都在那里,我想将其作为lambda传递来查找通用类型<T>的.Ssn属性。

编译时,出现这些错误。

错误43参数1:无法从'T'转换为'EFRGPayroll3G.CV.EarningsReportCV'C:\\ Users \\ Brown.Ericw \\ Documents \\ Visual Studio 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 Studio 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 Studio 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 Studio 2013 \\ Projects \\ WindowsService1 \\ WindowsService1 \\ BLL \\ RazorReportRenderBLL.cs 407 21 WindowsService1
错误'System.Collections.Generic.List<EFRGPayroll3G.CV.EarningsReportCV>.Add(EFRGPayroll3G.CV.EarningsReportCV)'的最佳重载方法匹配具有一些无效的参数C:\\ Users \\ Brown.Ericw \\ Documents \\ Visual Studio 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 );
        }
    }
}

并确保每个ReportCV都实现IHasSsn

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM