C#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) &

我在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) && 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很困惑:


  • 这种行为的原因是什么?component和GCPeak都是类,所以我希望对象和代码的引用而不是副本能够正常工作
  • 如何正确地做我想做的事情
  • 编辑:

    这就是我获取IEnumarables的方式(整个过程都来自一个XML文件——LINQ到XML)。获得化合物的方法基本相同

     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堆栈上完成的,因此我相信它会更快