具有自我引用的Lambda表达式 - 它在做什么?

时间:2014-07-29 01:56:33

标签: c# linq lambda

我遇到了需要调试的代码。它是集合上的过滤器,似乎可以引用自身。

tempSomeObjects = SomeObjects.SelectMany(fk => (from k1 in Lista
    from k2 in K1.Listb
    from k3 in k2.Listc
    from k4 in k3.Listd
    from k5 in k4.Liste
    where (k4.name1 + k5.name2) == fk
    select new SomeObjects(k4.name1, k5.name2, string.Empty, "ww"))).ToList();

我试图简化'如下所示

foreach (var k1 in Lista)
{
    foreach (var k2 in K1.Listb)
    {
        foreach (var k3 in k2.Listc)
        {
            foreach (var k4 in k3.Listd)
            {
                foreach (var k5 in k4.Liste)
                {
                    //This bit doesnt work like original ccode 
                    //as it simply gives me back everything in the liste

                    // The next few lines are what I need help with - as in what you
                    // think is trying to be selected based on the original code
                    tempSomeObject = new SomeObjects(
                        k4.name1, k5.name2, string.Empty, "ww");

                    if ((k4.name1 + k5.name2) ==
                        (tempSomeObject.name1, tempSomeObject))
                    {
                        tempSomeObjects.Add(tempSomeObject);
                    }

                }
            }
        }
    }
}

但我很确定我至少缺少一步,因为原始代码的过滤没有完成。 请告知fk正在做什么以及简化代码中的等效内容。

由于

2 个答案:

答案 0 :(得分:0)

在C#lambda表达式中,语法a => doSomethingWith(a)创建一个匿名函数,其中=>左侧的部分是函数的参数列表,右侧的部分是函数体。

因此,在您的神秘功能的情况下:

fk =>
    // ...
    where k4.name + k5.name == fk
    // ...

标识符fk引用SomeObjects中当前选定的项目,而不是表达式本身。 SelectMany是一个Linq方法,它枚举IEnumerable并返回一个新的平面IEnumerable,其中新集合中的每个元素都是在原始集合的元素上调用给定的匿名函数的结果

SomeObjects似乎是字符串的集合,对于每个字符串,我们希望从另一个集合中找到一些元素,这些元素是该字符串的互补子串。例如,如果fk"foobar",则可能会从"foo""bar"(或"f"和{{}创建结果的相应元素1}},就此而言)。

这个特定函数的确切语义取决于我们不知道的很多细节。

答案 1 :(得分:0)

您的扩展逻辑表明对Lamba和LINQ表达式尝试执行的操作存在根本性的误解。你错过了一个关于(我猜的)字符串集合的交互者,“SomeObjects”是一个包装器。您需要做的第一件事是利用调试器来确定“SomeObjects”的实际内容是什么。您可能还应该通过侦听器再次使用调试器来查看lista的内容。

您暗示对代码进行了一些手动模糊处理。列表中包含的列表是否随后实际上都是这样命名的?我只是问,因为我无法想象你有几个相同类型的嵌套列表(看起来对我来说),但每个递归层中有一个不同的名称。我猜奇怪的事情发生了......

现在考虑到我提供的信息,我猜测发生了什么。我在这里根据具体情况做了几次猜测,所以我可能都湿了。

SomeObjects(你为什么要把这个对象命名为类,包括大小写?)看起来像一个继承IEnumerable或类似的类,但是有一个构造函数接受4个字符串或者一个params字符串数组。我这样说是因为它的内容显然是经过迭代并比较为字符串。

嵌套列表对象稍微复杂一些,但name1和name2对象看起来又是字符串,看起来每个列表都有一个相同类型或类似类型的列表。所以...

对于SomeObjects中的每个字符串,迭代lista的listb,然后遍历listb的listc,然后遍历listc列表,然后遍历listd的liste。这是为了获取listd对象中的每个name1值,并获取liste对象中的每个name2。将这两个名称组合在一起,然后与顶部lambda表达式中由fk定义的字符串进行比较。如果匹配,则使用上面定义的四个字符串创建一个新的SomeObjects对象,并返回创建的每个SomeObject对象的列表。

最后,我将尝试在第二个示例中更正您的语法,虽然我无法验证它,因为我对您正在处理的对象一无所知......

var tempSomeObjects = new List<SomeObjects>();
foreach(var fk in SomeObjects)
{
    foreach(var k1 in lista)
    {
        foreach(var k2 in k1.listb)
        {
            foreach(var k3 in k2.listc)
            {
                foreach(var k4 in k3.listd)
                {
                    foreach(var k5 in k4.liste)
                    {
                        if ((k4.name1 + k5.name2) == fk)
                        {
                            tempSomeObjects.Add(new SomeObjects(k4.name1, k5.name2, string.Empty, "ww"));
                        }
                    }
                }
            }
        }
    }
} 

我没有看到任何类型的自我引用,但我确信代码可能会更加清晰。更多细节将有助于破译正在发生的事情或应该发生的事情,特别是如果您希望帮助清理或修复它。