C#foreach:不是指原始对象,而是指副本?
我在foreach循环中有一些奇怪的行为:C#foreach:不是指原始对象,而是指副本?,c#,foreach,reference,copy,C#,Foreach,Reference,Copy,我在foreach循环中有一些奇怪的行为: IEnumerable<Compound> loadedCompounds; ... // Loop through the peaks. foreach (GCPeak p in peaks) { // Loop through the compounds. foreach (Compound c in loadedCompounds) { if (c.IsInRange(p) &
IEnumerable<Compound> loadedCompounds;
...
// Loop through the peaks.
foreach (GCPeak p in peaks)
{
// Loop through the compounds.
foreach (Compound c in loadedCompounds)
{
if (c.IsInRange(p) && c.SignalType == p.SignalType)
{
c.AddPeak(p);
}
}
}
i可数负载化合物;
...
//穿过山峰。
foreach(峰值中的GCP峰值)
{
//在化合物中循环。
foreach(负载化合物中的化合物c)
{
如果(c.IsInRange(p)和c.SignalType==p.SignalType)
{
c、 AddPeak(p);
}
}
}
所以我想做的是:循环遍历所有的gcpeak(这是一个类),并将它们排序为相应的化合物
AddPeak只是将GCPeak添加到SortedList。代码编译和运行时不会出现异常,但问题是:
c.AddPeak(p)之后,c中的SortedList包含GCPeak(通过调试器检查),而LoadedComponents中的SortedList保持为空
我对我产生的这个bug很困惑:
IEnumerable<GCPeak> peaksFromSignal = from p in signal.Descendants("IntegrationResults")
select new GCPeak()
{
SignalType = signaltype,
RunInformation = runInformation,
RetentionTime = XmlConvert.ToDouble(p.Element("RetTime").Value),
PeakArea = XmlConvert.ToDouble(p.Element("Area").Value),
};
IEnumerable peaksFromSignal=来自signal.subjects(“IntegrationResults”)中的p
选择新的GCPeak()
{
信号类型=信号类型,
RunInformation=RunInformation,
RetentionTime=XmlConvert.ToDouble(p.Element(“RetTime”).Value),
PeakArea=XmlConvert.ToDouble(p.Element(“Area”).Value),
};
谢谢 IEnumerable不会硬引用您的列表。这会给您带来两个潜在问题 1) 您正在枚举的内容可能不再存在(例如,如果您使用诸如IEnumerable等惰性技术枚举facebook帖子列表,但您与facebook for的连接已关闭,则它可能计算为空枚举。如果您对数据库集合执行IEnumerable操作,但数据库连接已关闭等,也会发生同样的情况。) 2) 使用这样的枚举可能会导致您以后或以前进行多次枚举,这可能会有问题。Resharper通常会对此发出警告(以防止意外后果)。有关更多信息,请参阅此处:
要调试您的情况,您可以使用.toList()的LINQ扩展来强制提前计算IEnumerable。这将使您更容易查看IEnumerable中的内容,并让您在代码中遵循这一点。请注意与您目前使用的惰性引用相比,它确实具有性能影响,但它会更早地强制使用硬引用,帮助您调试场景,并避免上述场景对您造成挑战。谢谢您的评论 事实上,将我加载的化合物转换为列表是有效的 经验教训:小心使用IEnumerable 编辑 根据要求,我添加了AddPeak的实现:
public void AddPeak(GCPeak peak)
{
if (peak != null)
{
peaks.Add(peak.RunInformation.InjectionDateTime, peak);
}
}
RunInformation是一个结构。是一个结构还是一个类?如果你能提供足够的代码让我们轻松重现这个问题,那将是一个很大的帮助。因为
LoadedComponents
是一个可枚举的,可能不是一个真正的列表。试着调用LoadedComponents=LoadedComponents.ToList()
在第一个循环之前。component和GCPeak都是类。Kalten提出了一个很好的观点。确保你在两个循环中都列举了相同的component
实例——你向我们展示的实例,以及你发现峰值缺失的实例。恐怕我自己的问题很傻。loaded components
迭代器实现了吗?如果每次迭代器都在生成新的复合对象,那么所有数据都会丢失。谢谢,这帮了大忙。当回顾如何获取IEnumerable时:我正确地假设,在每次对IEnumarble求值时,它都是由LINQ从XML文件新创建的XML?如果是XML文件,则是XML文件吗计算IEnumerable时是否打开?它来自XDocument.Load(“文件名”)。但是,该XDocument仍在内存中。这是一种奇怪的行为,因为XDocument不可识别。你能包含c.AddPeak定义吗?我打赌答案为什么在这里?我认为这里没有学到教训。你不明白为什么要列出()解决了您的问题。否则,您可能会过多地使用toList()或重复错误。IEnumerable应该在您的情况下正常工作,除非您有错误(即.toList()正在隐藏)。我怀疑您正在以一种您不希望的方式修改集合。我非常感谢您与我一起进一步讨论此问题。我添加了AddPeak方法。这对我来说很危险,因为您正在使用内部循环修改外部foreach循环集合。这可能会产生意外的后果。我以前也曾为此感到痛苦。这对我来说非常危险像您这样的ems正在尝试用两个foreach循环来模拟递归。也许递归可以更好地工作?据我所知,递归是在cpu堆栈上完成的,因此我相信它会更快