关于foreach的C#LINQ问题

时间:2010-03-10 08:23:39

标签: 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.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;
            }
        }
    }
}

我认为这不是写它的正确方法。请指教。

7 个答案:

答案 0 :(得分:3)

如果不需要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();
}

答案 1 :(得分:2)

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

如果你可以从eventDoc开始 - 你可以过滤掉没有EAN的那些,然后从那里向后移动,但是我不能说这是多么可行,因为我错过了完整的模型(如:你可能没有后面的lniks,所以你会被事情困住,因为事件doc一个dcoul dnot不能到达该项目。

首先看起来很好看。

答案 2 :(得分:1)

我认为你需要itemNreventDocNr时,你会遇到每个循环。您可以使用for循环来避免增加itemNreventDocNr,但这不会减少循环次数。

修改

如果您需要 itemNreventDocNr,请尝试以下操作:

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
}

答案 3 :(得分:1)

您可以尝试以下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个错误的MEAN:我创建了像这样的嵌套结构

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}
                  }
             }
         }
    }
};

答案 4 :(得分:0)

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

var itemDocs = handOverDoc.Assignment.Items.Select((h,i)=&gt; new {item = h,itemindex = i})

您也可以为内部循环重复此过程,我怀疑您可以使用SelectMany()进一步简化它。

答案 5 :(得分:0)

你想在这里做两件不同的事情。首先,你试图找到一个文件,然后你试图根据它改变一些东西。该过程的第一个阶段只是澄清您已有的代码,例如

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

public void FindAndDisplayEventDocWithoutEAN(HandOverDoc handOverDoc)
{
    var eventDoc = FindEventDocWithoutEAN(handOverDoc);
    if (eventDoc != null)
    {
        Display(eventDoc);
    }
}

public EventDoc FindEventDocWithoutEAN(HandOverDoc handOverDoc)
{
    foreach(ItemDoc itemDoc in handOverDoc.Assignment.Items)
        foreach(ItemDetailDoc detail in itemDoc.Details) 
            foreach(EventDoc eventDoc in detail.Events)
                if(!eventDoc.HasEAN)  
                    return eventDoc;
    return null;
}

public void Display(EventDoc eventDoc)
{
    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();
}

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

嵌套的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();
}

答案 6 :(得分:0)

又一次旋转...

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();
}