有没有办法用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;
}
}
}
}
我认为这不是写它的正确方法。请指教。
答案 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)
我认为你需要itemNr
和eventDocNr
时,你会遇到每个循环。您可以使用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
}
答案 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();
}