简体   繁体   English

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

[英]Generics wtih anonymous Delegates expressed a lambdas… Ithink

So I'm trying to do something just slightly beyond the edge of my understanding... in three different ways. 因此,我正在尝试以三种不同的方式做一些超出我的理解范围的事情。 Let me explain what I'm trying to do then I'll get to the particulars of my lack of understanding. 让我解释一下我要做什么,然后我将了解我缺乏理解的细节。

I have several Dictionaries, that contain objects I need to generate reports. 我有几个词典,其中包含生成报告所需的对象。 they are all 他们都是

ConcurrentDictionary< Int64, List< EarningsReportCV>>

where earnings CV is a custom object that only contains properties(custom View model). 其中收益CV是仅包含属性的自定义对象(自定义视图模型)。

I have three of these dictionaries...and the code to init them is almost identical, they each just contain a different class CV. 我有三个这样的字典...并且初始化它们的代码几乎是相同的,它们每个都包含一个不同的CV类。

Here is one example: 这是一个例子:

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 );
        }
    }
}

All three Dictionaries are keyed off a string <T>.Ssn 所有三个字典均以字符串<T>.Ssn为键

Instead of having copy and paste code with just the types of the CV changing, I want to make a generic method. 我不希望仅通过更改CV的类型来复制和粘贴代码,而是要创建一个通用方法。 To do this I need to pass in a anonymous delegate that allows me to generically take the passed in type T and get it's .Ssn property to use as the key. 为此,我需要传入一个匿名委托,该委托使我可以通用地接受传入的T类型,并将其.Ssn属性用作键。

I googled and thought and read and got this far... 我用谷歌搜索,思考并阅读,并了解到了这一点...

Generic: 通用:

 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 );
         }
     }
 }

which I call thusly 我这样称呼

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
}

I think I get everything there except the 3r d parameter, which I want to pass in as a lambda to look up the .Ssn property of the generic type <T> . 除了3r d参数外,其他所有东西我都在那里,我想将其作为lambda传递来查找通用类型<T>的.Ssn属性。

When I compile it , I get these errors.. 编译时,出现这些错误。

Error 43 Argument 1: cannot convert from 'T' to 'EFRGPayroll3G.CV.EarningsReportCV' C:\\Users\\Brown.Ericw\\Documents\\Visual Studio 2013\\Projects\\WindowsService1\\WindowsService1\\BLL\\RazorReportRenderBLL.cs 406 33 WindowsService1 错误43参数1:无法从'T'转换为'EFRGPayroll3G.CV.EarningsReportCV'C:\\ Users \\ Brown.Ericw \\ Documents \\ Visual Studio 2013 \\ Projects \\ WindowsService1 \\ WindowsService1 \\ BLL \\ RazorReportRenderBLL.cs 406 33 WindowsService1
Error 45 Argument 2: cannot convert from 'System.Collections.Generic.List<EFRGPayroll3G.CV.EarningsReportCV>' to '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 错误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
Error 46 Argument 3: cannot convert from 'lambda expression' to '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 错误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
Error 44 The best overloaded method match for '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>>)' has some invalid arguments C:\\Users\\Brown.Ericw\\Documents\\Visual Studio 2013\\Projects\\WindowsService1\\WindowsService1\\BLL\\RazorReportRenderBLL.cs 407 21 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
Error 42 The best overloaded method match for 'System.Collections.Generic.List<EFRGPayroll3G.CV.EarningsReportCV>.Add(EFRGPayroll3G.CV.EarningsReportCV)' has some invalid arguments C:\\Users\\Brown.Ericw\\Documents\\Visual Studio 2013\\Projects\\WindowsService1\\WindowsService1\\BLL\\RazorReportRenderBLL.cs 406 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

and at that point I no longer understand what's going on...my brain is just full... what do I do to take this to a functional piece of code. 到那时我再也无法理解发生了什么...我的大脑已经满了...我该怎么做才能将其带入功能代码中。 I'm looking for both what to do, and what it is I need to grok to wrap my head around this and best of all good articles to explain it to me... Any even small glimmerings of understanding are greatly appreciated. 我正在寻找要做的事,也需要寻找什么,需要把我的头裹在这件事上,并且在所有最好的文章中向我解释一下。...

The line List<EarningsReportCV> cvList = new List<EarningsReportCV>(); List<EarningsReportCV> cvList = new List<EarningsReportCV>(); Should be using T , not EarningsReportCV . 应该使用T ,而不是EarningsReportCV

You made your function generic but simply forgot to change those two instances of the old concrete class to the generic type. 您使函数成为泛型,但只是忘记将旧的具体类的这两个实例更改为泛型。 The method compiles after that change. 该更改后将编译该方法。

Having said that, there are several issues that you should probably change in your function. 话虽如此,您可能应该在功能上更改几个问题。

First and foremost, it appears to attempt to be safe to be called from multiple threads, but it's not. 首先,从多个线程进行调用似乎很安全,但事实并非如此。 A key could be added or removed in another thread after you check to see if it exists, resulting in items being dropped on the floor. 在检查钥匙是否存在之后,可以在另一个线程中添加或删除钥匙,从而导致物品掉落在地板上。

The premise of your program is to add an item if it's not there, and update it if it is. 程序的前提是添加不存在的项目,如果存在则进行更新。 That exactly what AddOrUpdate is designed to do, atomically. 正是 AddOrUpdate旨在自动完成的工作。 You should simply be calling that once, rather than what you're doing. 您应该只打一次电话,而不是在做什么。 It even makes the code simpler. 它甚至使代码更简单。

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;
            });
    }
}

There are some other changes that you can make to improve the code as well. 您还可以进行其他一些更改来改进代码。 Since you only ever iterate list and never do anything else, you can make that parameter an IEnumerable , allowing it to be any type of sequence beyond just lists. 由于您只迭代list而从不执行任何其他操作,因此可以将该参数设置为IEnumerable ,从而使其可以是除列表之外的任何类型的序列。

If you're program is designed to be accessing and manipulating theDict from multiple threads, it's very likely that the inner lists shouldn't be lists, but should be a collection designed to be accessed from multiple threads, such as a ConcurrentBag . 如果您的程序旨在从多个线程访问和操作theDict ,则内部列表很可能不应该是列表,而应该是一个旨在从多个线程访问的集合,例如ConcurrentBag

Since the delegate you're accepting really wants a long , not a string , that's really what it should accept, rather than accepting a string and trying to convert it. 由于您要接受的委托确实需要long而不是string ,所以这实际上是它应该接受的,而不是接受string并尝试将其转换。

This gives us: 这给我们:

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;
            });
    }
}

Since all three use .Ssn you don't need a access Func<> . 由于这三个都使用.Ssn您不需要访问Func<> You need to tell the method they all have an Ssn: 您需要告诉他们它们都有一个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 );
        }
    }
}

And make sure each ReportCV implements IHasSsn 并确保每个ReportCV都实现IHasSsn

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

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