0

我试图从我附加的库对象列表中获取我的信息对象中的数据。我拥有的两种解决方案似乎都非常低效。有没有办法将其减少为单个 OfType 调用,而 linq 查询不是更长的变体?

using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqQueries
{

    // Test the linq queries
    public class Test
    {
        public void TestIt()
        {
            List<ThirdParty> As = new List<ThirdParty>();

            // This is nearly the query I want to run, find A and C where B 
            // and C match criteria
            var cData = from a in As
                        from b in a.myObjects.OfType<MyInfo>()
                        where b.someProp == 1
                        from c in b.cs
                        where c.data == 1
                        select new {a, c};

            // This treats A and B as the same object, which is what I
            // really want, but it calls two sub-queries under the hood, 
            // which seems less efficient 
            var cDataShorter = from a in As
                               from c in a.GetCs()
                               where a.GetMyProp() == 1
                               where c.data == 1
                               select new { a, c };
        }
    }

    // library class I can't change
    public class ThirdParty
    {
        // Generic list of objects I can put my info object in
        public List<Object> myObjects;
    }

    // my info class that I add to ThirdParty
    public class MyInfo
    {
        public List<C> cs;
        public int someProp;
    }

    // My extension method for A to simplify some things.
    static public class MyExtentionOfThirdPartyClass
    {
        // Get the first MyInfo in ThirdParty
        public static MyInfo GetB(this ThirdParty a)
        {
            return (from b in a.myObjects.OfType<MyInfo>()
                    select b).FirstOrDefault();
        }

        // more hidden linq to slow things down...
        public static int GetMyProp(this ThirdParty a)
        {
            return a.GetB().someProp;
        }

        // get the list of cs with hidden linq
        public static List<C> GetCs(this ThirdParty a)
        {
            return a.GetB().cs;
        }
    }

    // fairly generic object with data in it
    public class C
    {
        public int data;
    }
}
4

2 回答 2

1

如果您说您cDataShorter正在产生正确的结果,那么您可以像这样重写它:

As.SelectMany(a => a.myObjects, (aa, mo) => new R {Tp = aa, Mi = mo as MyInfo})
  .Where(r => r.Mi != null && r.Mi.someProp == 1)
  //.Distinct(new Comparer<R>((r1, r2) => r1.Tp.Equals(r2.Tp))) 
  // If you need only one (first) MyInfo from a ThirdParty 
  // You don't need R if you're not going to use Distinct, just use an anonymous
  .SelectMany(r => r.Mi.cs, (rr, c) => new {a = rr.Tp, c})
  .Where(ao => ao.c.data == 1)      

public class R {
    public ThirdParty Tp;
    public MyInfo Mi;
}

为简单起见,Comparer那里

于 2013-03-07T21:40:46.580 回答
1

不幸的是,答案是“视情况而定”。我必须以两种方式编写查询并对其进行计时。

1000 个第三方对象,每个 1 个 MyObject,每个 1000 个 c,所有结果都符合条件,第一次查询速度是原来的两倍。如果没有 MyObjects 符合条件,则查询 1 的速度要快两个数量级。但是,如果你有多个MyObjects,效率倒转,100个ThirdParty,100个MyObjects,每个100个C,所有结果匹配,第二个查询比第一个快两个数量级。没有 MyObjects 匹配,第一个出来得更快。

实际上,我最终实施了较慢的解决方案,因为它使代码更清晰,而且较慢查询的性能也不是那么糟糕。

于 2013-04-18T15:14:20.093 回答