Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
关于foreach的C#LINQ问题_C#_Linq - Fatal编程技术网

关于foreach的C#LINQ问题

关于foreach的C#LINQ问题,c#,linq,C#,Linq,有没有办法用linq或其他更好的方式来写这个foreach int itemNr = -1; foreach(ItemDoc itemDoc in handOverDoc.Assignment.Items) { itemNr++; foreach(ItemDetailDoc detail in itemDoc.Details) { int eventDocNr = -1; foreach(EventDoc eventDoc in detail.

有没有办法用linq或其他更好的方式来写这个foreach

int itemNr = -1;
foreach(ItemDoc itemDoc in handOverDoc.Assignment.Items) {

    itemNr++;
    foreach(ItemDetailDoc detail in itemDoc.Details) {
        int eventDocNr = -1;

        foreach(EventDoc eventDoc in detail.Events) {
            eventDocNr++;

            if(!eventDoc.HasEAN) {
                HideShowPanels(pMatch);
                txt_EAN.Text = String.Empty;

                lbl_Match_ArtName.Text = itemDoc.Name;
                lbl_ArtNr.Text = itemDoc.Number;
                lbl_unitDesc.Text = eventDoc.Description;

                m_tempItemNr = itemNr;
                m_tempEventNr = eventDocNr;
                txt_EAN.Focus();

                return;
            }
        }
    }
}

我只是觉得这不是正确的写作方式。请告知。

我认为您需要
itemNr
eventDocNr
的for-each循环。您可以使用
for
循环来避免增加
itemNr
eventDocNr
,但这不会减少循环的数量

编辑:

如果您确实需要
itemNr
eventDocNr
,请尝试以下操作:

var query = handOverDoc.Assignment.Items
                       .SelectMany(
                           (x, i) => x.Details.SelectMany(
                               (d, di) => d.Events.Where(x => x.HasEAN).Select(
                                   (e, ei) => new { 
                                       ItemIndex = di, 
                                       EventIndex = ei, 
                                       Detail = d,
                                       Event = e 
                                   }
                                )
                            )
                        );
foreach (var eventInfo in query) {
    HideShowPanels(pMatch);
    txt_EAN.Text = String.Empty;

    lbl_Match_ArtName.Text = eventInfo.Detail.Name;
    lbl_ArtNr.Text = eventInfo.Detail.Number;
    lbl_unitDesc.Text = eventInfo.Event.Description;

    txt_EAN.Focus();

    return;     
}
如果您只需要带有EAN的第一个事件,您还可以在上述查询中使用以下内容:

var item = query.FirstOrDefault();
if (item != null) {
    // do you stuff here
}

不,我认为没有更好的办法。LINQ是关于查询的,您在那里做了很多处理。除非你有一条在这里不明显的捷径。。。。这似乎不是唯一的办法

如果你可以从eventDoc开始-你可以过滤掉那些没有EAN的,然后从那里向后走,但是我不能说这有多可行,因为我错过了完整的模型(比如:也许你没有背面的lniks,所以你会被eventDoc卡住,无法进入项目)


首先看起来不错。

您可以尝试以下LINQ:

var nonEANs = from ItemDoc itemDocs in itemDocList
              from ItemDetailDoc itemDetailDocs in itemDocs.Details
              from EventDoc eventDocs in itemDetailDocs.Events
              where !eventDocs.HasEAN
              select eventDocs;


foreach (var i in nonEANs)
{
    System.Diagnostics.Debug.WriteLine( i.HasEAN);
}
应该返回7个假EANs:我重新创建了这样的嵌套结构

List<ItemDoc> itemDocList = new List<ItemDoc>()
{
    new ItemDoc() 
    {
         Details = new List<ItemDetailDoc>()
         {
             new ItemDetailDoc()
             {
                  Events = new List<EventDoc>()
                  {
                      new EventDoc()
                      {HasEAN=false},
                      new EventDoc()
                      {HasEAN=false}
                  }
             },
             new ItemDetailDoc()
             {
                  Events = new List<EventDoc>()
                  {
                      new EventDoc()
                      {HasEAN=true},
                      new EventDoc()
                      {HasEAN=false}
                  }
             }
         }
    },
    new ItemDoc() 
    {
         Details = new List<ItemDetailDoc>()
         {
             new ItemDetailDoc()
             {
                  Events = new List<EventDoc>()
                  {
                      new EventDoc()
                      {HasEAN=false},
                      new EventDoc()
                      {HasEAN=false}
                  }
             },
             new ItemDetailDoc()
             {
                  Events = new List<EventDoc>()
                  {
                      new EventDoc()
                      {HasEAN=false},
                      new EventDoc()
                      {HasEAN=false}
                  }
             }
         }
    }
};
List itemDocList=新列表()
{
新项目文档()
{
详细信息=新列表()
{
新的ItemDetailDoc()
{
事件=新列表()
{
新事件文档()
{HasEAN=false},
新事件文档()
{HasEAN=false}
}
},
新的ItemDetailDoc()
{
事件=新列表()
{
新事件文档()
{HasEAN=true},
新事件文档()
{HasEAN=false}
}
}
}
},
新项目文档()
{
详细信息=新列表()
{
新的ItemDetailDoc()
{
事件=新列表()
{
新事件文档()
{HasEAN=false},
新事件文档()
{HasEAN=false}
}
},
新的ItemDetailDoc()
{
事件=新列表()
{
新事件文档()
{HasEAN=false},
新事件文档()
{HasEAN=false}
}
}
}
}
};

如果不需要itemNr和eventDocNr,您可以使用:

var item =
            (from itemDoc in handOverDoc.Assignment.Items
             from detail in itemDoc.Details
             from eventDoc in detail.Events
             where !eventDoc.HasEAN
             select new 
                {
                    Name = itemDoc.Name,
                    Number = itemDoc.Number,
                    Description = eventDoc.Description 
                }).FirstOrDefault();

if (item != null)
{
    HideShowPanels(pMatch);
    txt_EAN.Text = String.Empty;

    lbl_Match_ArtName.Text = item.Name;
    lbl_ArtNr.Text = item.Number;
    lbl_unitDesc.Text = item.Description;

    txt_EAN.Focus();
}

您可以很容易地在LINQ中获取索引,例如:-

var itemDocs=handOverDoc.Assignment.Items.Select((h,i)=>new{item=h,itemdex=i})


你也可以对你的内部循环重复这个过程,我想你可以使用SelectMany()进一步简化。

您在这里尝试做两件不同的事情。首先,您尝试查找文档,其次,您尝试根据文档更改内容。流程的第一阶段只是澄清您已经拥有的代码,例如

(注意,这考虑了之前的注释,即原始代码中不需要计算索引。无论是否需要计算索引,都可以将完全相同的类型拆分为两种方法,并且仍然可以改进原始代码。)

完成后,您应该能够看到一个方法是对主文档的查询,另一个是显示查询结果的方法。这就是所谓的单一责任原则,其中每个方法都做一件事,并以其所做的事情命名

将嵌套的foreach循环转换为linq查询现在几乎是微不足道的。将下面的方法与上面的方法进行比较,您可以看到将嵌套的foreach循环转换为linq查询是多么机械

public EventDoc FindEventDocWithoutEAN(HandOverDoc handOverDoc)
{
    return (from itemDoc in handOverDoc.Assignment.Items
            from detail in itemDoc.Details
            from eventDoc in detail.Events
            where !eventDoc.HasEAN
            select eventDoc).FirstOrDefault();
}
又一个旋转

var query = from itemDocVI in handOverDoc.Assignment
                                     .Items
                                     .Select((v, i) => new { v, i })
            let itemDoc = itemDocVI.v
            let itemNr = itemDocVI.i
            from detail in itemDoc.Details
            from eventDocVI in detail.Events
                                     .Select((v, i) => new { v, i })
            let eventDoc = eventDocVI.v
            let eventDocNr = eventDocVI.i
            where eventDoc.HasEAN
            select new
            {
                itemDoc,
                itemNr,
                detail,
                eventDoc,
                eventDocNr
            };

var item = query.FirstOrDefault();
if (item != null)
{
    HideShowPanels(pMatch);
    txt_EAN.Text = String.Empty;

    lbl_Match_ArtName.Text = item.itemDoc.Name;
    lbl_ArtNr.Text = item.itemDoc.Number;
    lbl_unitDesc.Text = item.eventDoc.Description;

    m_tempItemNr = item.itemNr;
    m_tempEventNr = item.eventDocNr;
    txt_EAN.Focus();
}

但是,如果我不再需要itemNr和eventDocNr。有没有更好的方法来编写此内容?Select有一个提供索引的重载,请参阅我的答案。itemDoc没有声明,因此您将无法从中提取名称和编号。这样,您只能访问eventDoc。谢谢您,Cornelius。我编辑了此帖子。现在可以访问po了sitions和ItemDoc已启用。嗨,TomTom,您还可以使用LINQ查询内存中的对象结构以及LINQ到SQL/Entities。不相关-我没有这样做。问题是,如果您有一个eventDoc列表,但没有指向该项目的指针,那么查询该列表将无法提供与此查询相同的内容。恐怕我会我不同意这一点。即使它没有重写为linq,也可以通过拆分成多个方法,将他正在执行的两个操作分离为一个块来显著改进。不一样。请注意他如何需要循环中的索引来进行进一步的操作。您将无法访问itemDoc中的名称和描述只有eventDoc被选中。不允许访问ItemDoc的名称和描述,因此,它不会与循环中的代码一起工作。他从哪里获得itemNr和eventDocNr?@Hightechrider-我已经解释过,根据他对其他答案的评论,我没有包括它们,并且主要转换为两种方法ods在这两种情况下都是有效的。在查询中设置模块级状态几乎总是错误的方法,所以我假设该部分也将得到改进,不再需要这些索引。
var query = from itemDocVI in handOverDoc.Assignment
                                     .Items
                                     .Select((v, i) => new { v, i })
            let itemDoc = itemDocVI.v
            let itemNr = itemDocVI.i
            from detail in itemDoc.Details
            from eventDocVI in detail.Events
                                     .Select((v, i) => new { v, i })
            let eventDoc = eventDocVI.v
            let eventDocNr = eventDocVI.i
            where eventDoc.HasEAN
            select new
            {
                itemDoc,
                itemNr,
                detail,
                eventDoc,
                eventDocNr
            };

var item = query.FirstOrDefault();
if (item != null)
{
    HideShowPanels(pMatch);
    txt_EAN.Text = String.Empty;

    lbl_Match_ArtName.Text = item.itemDoc.Name;
    lbl_ArtNr.Text = item.itemDoc.Number;
    lbl_unitDesc.Text = item.eventDoc.Description;

    m_tempItemNr = item.itemNr;
    m_tempEventNr = item.eventDocNr;
    txt_EAN.Focus();
}