使用 LINQ(集合中的集合)简化代码

发布于 2024-11-27 20:21:28 字数 1076 浏览 6 评论 0原文

给定一个如下所示的对象图;

A --> B[] --> B1[]
          --> B2[]   
  --> C[]

我需要检查 B1 和 B2 的成员/属性的某些条件,并确保 b2.Code 出现在 C[] 内的某个位置。如果满足所有条件,我需要使用 C 和 B 数组元素中的变量构造一个新对象。我当前的尝试如下所示,但我想知道是否可以使用 LINQ 使其更加简洁?

   A a = GetA();
   List<MyTest> tsts = new List<MyTest>();
   foreach (B b in a.B)
    {
        foreach (B1 b1 in b.B1)
        {
            if (b1.State == ("READY"))
            {
                foreach (B2 b2 in b.B2)
                {
                    var tst = (from c in a.C
                           where c.Code == b2.Code && !c.IsRedundant
                           select new MyTest
                           {
                               Code = c.Code,
                               BVal = b.BVal,
                               C1Val = c.C1                     
                           }).FirstOrDefault();
                    if (tst != null)
                        tsts.Add(tst);
                    break;
                }
            }
        }
    }

Given an object graph that looks something like the following;

A --> B[] --> B1[]
          --> B2[]   
  --> C[]

I need to check certain conditions on members/properties of B1 and B2 as well as ensuring that b2.Code appears somewhere within the C[]. If all conditions are satisfied, I then need to construct a new object using variables from elements of the C and B array. My current attempt is shown below, but I am wondering if this could be made more concise with LINQ?

   A a = GetA();
   List<MyTest> tsts = new List<MyTest>();
   foreach (B b in a.B)
    {
        foreach (B1 b1 in b.B1)
        {
            if (b1.State == ("READY"))
            {
                foreach (B2 b2 in b.B2)
                {
                    var tst = (from c in a.C
                           where c.Code == b2.Code && !c.IsRedundant
                           select new MyTest
                           {
                               Code = c.Code,
                               BVal = b.BVal,
                               C1Val = c.C1                     
                           }).FirstOrDefault();
                    if (tst != null)
                        tsts.Add(tst);
                    break;
                }
            }
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

他是夢罘是命 2024-12-04 20:21:28

绝对地。基本上每个新的 foreach 大致相当于一个额外的 from 子句:

var tests = from b in GetA().B
            from b1 in b.B1
            where b1.State == "READY"
            from b2 in b.B2.Take(1)
            from c in a.C
                       .Where(x => x.Code == b2.Code && !c.IsRedundant)
                       .Take(1)
            select new MyTest
            {
                Code = c.Code,
                BVal = b.BVal,
                C1Val = c.C1                     
            };

var testList = tests.ToList();

对此的一些注释:

  • 您从未真正使用过 b1 ,这似乎很奇怪,但您将为每个处于“就绪”状态的 b1 创建一组额外的测试。
  • foreach (B2 b2 ...) 循环中的无条件 break 基本上意味着我们只执行一次循环体 - 因此 Take(1) code>
  • 仅使用最内层查询的第一个结果的方式就是为什么我通过 Take(1) 调用获得内部查询(通过扩展方法表示)以获取最多一个结果

它是其中一些奇怪的现象很可能可以被消除——但尚不清楚您真正想要实现什么,所以我只是尝试让代码尽可能忠实地重现您的原始查询。

Absolutely. Basically each new foreach roughly equates to an extra from clause:

var tests = from b in GetA().B
            from b1 in b.B1
            where b1.State == "READY"
            from b2 in b.B2.Take(1)
            from c in a.C
                       .Where(x => x.Code == b2.Code && !c.IsRedundant)
                       .Take(1)
            select new MyTest
            {
                Code = c.Code,
                BVal = b.BVal,
                C1Val = c.C1                     
            };

var testList = tests.ToList();

A few notes on this:

  • It seems odd that you're never actually using b1, but you'll create an extra set of tests for each b1 which is in the "ready" state.
  • The unconditional break within the foreach (B2 b2 ...) loop basically means we only ever execute the loop body once - hence the Take(1)
  • The way you only use the first result of the innermost query is why I've got the inner query (expressed through extension methods) with a Take(1) call to get at most one result

It's quite possible that some of these oddities can be removed - but it's not clear what you're really trying to achieve, so I've just tried to make the code reproduce your original query as faithfully as possible.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文