循环IEnumerator <t>,任何建议</t>

时间:2012-06-28 15:29:28

标签: c# linq ienumerable

我遇到的情况是循环LINQ的结果让我很紧张。那么这就是我的情景:

我有一个来自数据库的DataTable,我从中获取数据:

var results = from d in dtAllData.AsEnumerable()
              select new MyType
              {
                  ID = d.Field<Decimal>("ID"),
                  Name = d.Field<string>("Name")
              }

根据排序顺序执行订单后:

if(orderBy != "")
{
string[] ord = orderBy.Split(' ');
if (ord != null && ord.Length == 2 && ord[0] != "")
                        {
                            if (ord[1].ToLower() != "desc")
                            {
                                results = from sorted in results
                                          orderby GetPropertyValue(sorted, ord[0])
                                          select sorted;
                            }
                            else
                            {
                                results = from sorted in results
                                          orderby GetPropertyValue(sorted, ord[0]) descending
                                          select sorted;
                            }
                        }
}

GetPropertyValue方法如下:

private object GetPropertyValue(object obj, string property)
    {
        System.Reflection.PropertyInfo propertyInfo = obj.GetType().GetProperty(property);
        return propertyInfo.GetValue(obj, null);
    }

在此之后,我将为第一页取出25条记录,如:

results = from sorted in results
          .Skip(0)
          .Take(25)
          select sorted;

到目前为止事情进展顺利,现在我必须将这个结果传递给一个方法,该方法将对数据进行一些操作并返回所需的数据,这里我想循环这25条记录花了足够的时间。我的方法定义是:

public MyTypeCollection GetMyTypes(IEnumerable<MyType> myData, String dateFormat, String offset)

我已经尝试foreach并且在我的机器上需要8-10秒,这需要时间:

foreach(var _data in myData)

我尝试了while循环并且正在做同样的事情,我使用它像:

var enumerator = myData.GetEnumerator();
while(enumerator.MoveNext())
{
    int n = enumerator.Current;
   Console.WriteLine(n);
}

这段代码花时间在MoveNext

比我去for循环一样:

int length = myData.Count();
for (int i = 0; i < 25;i++ )
{
     var temp = myData.ElementAt(i);
}

此代码需要时间ElementAt

任何人都可以指导我,我做错了什么。我在VS 2008中使用Framework 3.5。

提前致谢

3 个答案:

答案 0 :(得分:3)

编辑:我怀疑问题在于您的订购方式。您使用反射首先获取,然后为每个记录调用属性。即使您只需要前25条记录,它也必须首先在所有记录上调用GetPropertyValue,以便对它们进行排序。

如果你可以在没有反射的情况下做到这一点,那将会更好 ...但如果你需要使用反射,至少要调用{{1} } 一次而不是每条记录。


(在某些方面,这更多地与帮助您比完整答案更容易诊断问题有关......)

正如亨克所说,这很奇怪:

Type.GetProperty()

你几乎肯定真的只是想要:

results = from sorted in results
          .Skip(0)
          .Take(25)
          select sorted;

results = results.Take(25); 毫无意义。)

它可能实际上没有帮助,但它会使代码更容易调试。

下一个问题是我们实际上无法看到您的所有代码。你写过:

  

根据排序顺序执行订单

...但您尚未显示 您正在执行订购的方式。

您应该向我们展示从Skip(0)到其使用的完整示例。

更改迭代序列的方式将帮助 - 无论是哪种方式都会做同样的事情 - 尽管令人惊讶的是,在您的上一次尝试中,DataTable显然很快就能正常工作。坚持Count() - 但确切地解决了将要做的事情。 LINQ使用了很多懒惰的评估,如果你做了一些非常重要的事情,可能成为问题。没有看到整个管道就很难知道。

答案 1 :(得分:0)

问题是你的“结果”IEnumerable实际上并没有被评估,直到它被传递到你的方法并被枚举。这意味着整个操作,从dtAllData获取所有数据,选择新类型(发生在整个可枚举,而不仅仅是前25个),然后最后是take 25操作,都发生在第一个枚举IEnumerable(foreach,while,无论如何)。

这就是为什么你的方法需要这么长时间。它实际上正在做一些在方法内部定义的工作。如果你希望在你的方法之前发生这种情况,你可以在方法之前做一个“ToList()”。

答案 2 :(得分:0)

您可能会发现采用混合方法更容易;

按顺序:

1)对您的数据表进行原位排序。最好在数据库级别执行此操作,但是,如果不能,那么DataTable.DefaultView.Sort非常有效:

dtAllData.DefaultView.Sort = ord[0] + " " + ord[1];

这假设ord [0]是列名,而ord [1]是ASC或DESC

2)通过索引编辑DefaultView:

int pageStart = 0;

List<DataRowView> pageRows = new List<DataRowView>();

for (int i = pageStart; i < dtAllData.DefaultView.Count; i++ )
{
   if(pageStart + 25 > i || i == dtAllData.DefaultView.Count - 1) { break; //Exit if more than the number of pages or at the end of the rows }
   pageRows.Add(dtAllData.DefaultView[i]);
}

...并从这个小得多的列表中创建你的对象......(我假设这些列被称为Id和Name,以及类型)

List<MyType> myObjects = new List<MyType>();

foreach(DataRowView pageRow in pageRows)
{
  myObjects.Add(new MyObject() { Id = Convert.ToInt32(pageRow["Id"]), Name = Convert.ToString(pageRow["Name"])});
}

然后,您可以继续完成剩下的工作。