C#foreach:不是引用原始对象,而是副本?

时间:2017-03-27 20:02:48

标签: 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) && c.SignalType == p.SignalType)
         {
             c.AddPeak(p);
         }  
     }
 }

所以我想做的事情:遍历所有GCPeaks(它是一个类)并将它们分类为相应的化合物。

AddPeak只是将GCPeak添加到SortedList。代码编译和运行没有例外,但问题是:

在c.AddPeak(p)之后,c中的SortedList包含GCPeak(使用Debugger检查),,而loadedCompounds中的SortedLists保持为空

我对我制作的这个错误非常困惑:

  1. 这种行为的原因是什么? Compound和GCPeak都是类,所以我希望引用而不是我的对象和代码的副本才能工作。
  2. 如何做我想做的事情?
  3. 修改

    这就是我获取IEnumarables的方式(整个过程来自XML文件 - LINQ to 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),
                                            };
    

    谢谢!

2 个答案:

答案 0 :(得分:0)

IEnumerable赢得了对您的列表的硬引用。这会给您带来两个潜在的问题。

1)你所枚举的内容可能不再存在(例如,如果你使用惰性技术(如IEnumerable等)枚举facebook帖子列表,但是你关于facebook的连接已关闭,那么它可能会评估为空如果您在数据库集合上执行IEnumerable但该数据库连接已关闭等,则会发生同样的情况。

2)使用类似的枚举可能会导致您稍后或之前执行多重枚举,这可能会产生问题。 Resharper通常会对此发出警告(以防止出现意外后果)。有关详细信息,请参阅此处:Handling warning for possible multiple enumeration of IEnumerable

你可以做的调试你的情况是使用.toList()的LINQ扩展来强制早期评估你的IEnumerable。这将让您更容易地看到IEnumerable中的内容,并允许您通过代码执行此操作。请注意,与当前的惰性引用相比,执行toList()确实会产生性能影响,但它会提前强制引用硬件并帮助您调试场景,并避免上述情况给您带来挑战。

答案 1 :(得分:0)

感谢您的评论。

确实将我加载的化合物转换为List&lt;&gt;工作。

获得的经验教训:小心IEnumerable。

修改 根据要求,我正在添加AddPeak的实现:

public void AddPeak(GCPeak peak)
{
    if (peak != null)
    {
        peaks.Add(peak.RunInformation.InjectionDateTime, peak);
    }
}

RunInformation是一个结构。