关于foreach的C#LINQ问题
有没有办法用linq或其他更好的方式来写这个foreach关于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.
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();
}