【问题标题】:C# Anonymous type foreach loop, a better way?C#匿名类型foreach循环,更好的方法?
【发布时间】:2013-01-09 19:10:31
【问题描述】:

我有一个匿名类型的简单foreach 循环,我想知道是否有办法让它更高效。

如果循环遍历 155 个项目,大约需要 20 秒才能完成。我省略了它在 boAsset 对象上设置的一些其他属性,但没什么特别的 - 只是 Strings/Integers

有什么想法吗?

List<BoAsset> assetList = new List<BoAsset>();
foreach (var asset in result)
{
     BoAsset boAsset = new BoAsset();
     boAsset.Description = asset.Description;
     boAsset.DetailedDescription = asset.DetailedDescription;
     boAsset.AssetCustomerID = asset.AssetCustomerID;
     boAsset.AssetId = asset.AssetId;
     boAsset.Keywords = asset.Keywords;
     boAsset.Notes = asset.Notes;
     boAsset.Photographer = asset.Photographer;
     boAsset.PhotographerEmail = asset.PhotographerEmail;
     boAsset.Notes = asset.Notes;
     boAsset.Author = asset.Author;
     boAsset.FileName = asset.FileName;
     boAsset.FileExtension = asset.FileExtension;
     boAsset.AssetCreateDate = asset.AssetCreateDate;
     boAsset.AssetExpireDate = asset.AssetExpireDate;

     assetList.Add(boAsset);
}


var query =   (from a in context.Assets
              join subAf1 in context.AssetFiles on new { aid = a.AssetID, ftid = 1 } equals new { aid = subAf1.AssetID, ftid = subAf1.AssetTypeID } into theAf1
              from Af1 in theAf1.DefaultIfEmpty()
              join subAf2 in context.AssetFiles on new { aid = a.AssetID, ftid = 2 } equals new { aid = subAf2.AssetID, ftid = subAf2.AssetTypeID } into theAf2
              from Af2 in theAf2.DefaultIfEmpty()
              join subAf3 in context.AssetFiles on new { aid = a.AssetID, ftid = 3 } equals new { aid = subAf3.AssetID, ftid = subAf3.AssetTypeID } into theAf3
              from Af3 in theAf3.DefaultIfEmpty()
              join subAf4 in context.AssetFiles on new { aid = a.AssetID, ftid = 4 } equals new { aid = subAf4.AssetID, ftid = subAf4.AssetTypeID } into theAf4
              from Af4 in theAf4.DefaultIfEmpty()
              join subAf5 in context.AssetFiles on new { aid = a.AssetID, ftid = 5 } equals new { aid = subAf5.AssetID, ftid = subAf5.AssetTypeID } into theAf5
              from Af5 in theAf5.DefaultIfEmpty()
              join subFp in context.FilePaths on new { fpid = Af1.FilePathID } equals new { fpid = subFp.FilePathID } into theFp1
              from fp1 in theFp1.DefaultIfEmpty()
              //join fp in context.FilePaths on Af1.FilePathID equals fp.FilePathID

              where a.AssetCustomerID == custId && a.AssetID == assetId
              select new { a, Af1, Af2, Af3, Af4, Af5, fp1 }).Distinct();

var result =   from q in query
               select new
               {
                   AssetId = q.a.AssetID,
                   AssetCustomerId = q.a.AssetCustomerID,
                   StockImage = q.a.StockImage,
                   Description = q.a.Description,
                   DetailedDescription = q.a.DetailedDescription,
                   Author = q.a.Author,
                   FileName = q.Af1.FileName, //was 1
                   FileExtension = q.Af1.FileExtension, //was 1
                   AssetCreateDate = q.a.AssetCreateDate,
                   AssetExpireDate = q.a.AssetExpireDate,
                   AssetActivateDate = q.a.AssetActivateDate,

                   Notes = q.a.Notes,
                   Keywords = q.a.Keywords,
                       Photographer = q.a.Photographer,
                       PhotographerEmail = q.a.PhotographerEmail
               }

【问题讨论】:

  • 你到底在哪里使用匿名类型?
  • 匿名类型是哪一部分?
  • 你必须发布动态对象“结果”是o.O
  • 循环遍历 155 个项目实际上并没有那么多工作,除非在循环中执行了您未显示的昂贵操作。 result 是什么?是查询吗?执行该查询可能会消耗您的时间,无论是预先还是在您迭代时,具体取决于查询的编写方式和功能。
  • 如果resultIEnumerable,则可能是底层来源很慢..

标签: c# performance linq foreach anonymous-types


【解决方案1】:

创建 155 个对象并将数据复制到其中的时间大约是一毫秒。您无法对该代码进行任何重大(甚至是显着)改进。

如果您想节省任何时间,您应该查看创建结果的查询。这需要时间。

【讨论】:

  • 我在 foreach 循环的开头放了一个断点...运行循环只需要 20 秒。
  • 你真的需要告诉我们结果是如何定义的
  • @user1541559:定义时不读取结果,在循环中使用时读取,也就是说读取结果的时间包含在20秒内。你可以先在结果上使用ToList,将其读入一个列表,然后在循环中使用该列表,你会看到实际上花了20秒来读取结果。
【解决方案2】:

我认为您的查询过于复杂(连接太多),尤其是考虑到有一些甚至没有使用。

请注意,如果查询很复杂,某些 LINQ 提供程序(例如 LINQ to Entities)可能需要相当长的时间来简单地处理查询树以将其转换为 SQL。 (我已经有一些查询需要 10 或 15 秒才能让 EF 对其进行分析。)

如果我怀疑您正在使用的 LINQ 实现正在访问数据库,那么请使用 SQL 分析工具来检查正在传递给服务器的实际 SQL 以及该 SQL 的性能如何。

另外,请注意,鉴于您正在使用的字段,您实际上可以通过将结果直接具体化到 BoAsset 对象中来取消 foreach 循环。

即:

var result = from q in query
             select new BoAsset
             {
                 AssetId = q.a.AssetID,
                 AssetCustomerId = q.a.AssetCustomerID,
                 StockImage = q.a.StockImage,
                 Description = q.a.Description,
                 DetailedDescription = q.a.DetailedDescription,
                 Author = q.a.Author,
                 FileName = q.Af1.FileName, //was 1
                 FileExtension = q.Af1.FileExtension, //was 1
                 AssetCreateDate = q.a.AssetCreateDate,
                 AssetExpireDate = q.a.AssetExpireDate,
                 AssetActivateDate = q.a.AssetActivateDate,
                 Notes = q.a.Notes,
                 Keywords = q.a.Keywords,
                 Photographer = q.a.Photographer,
                 PhotographerEmail = q.a.PhotographerEmail
             };

List<BoAsset> assetList = result.ToList();

【讨论】:

    猜你喜欢
    • 2010-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-04
    • 1970-01-01
    • 2019-04-17
    相关资源
    最近更新 更多