引用IEEumerable的XElements

时间:2011-08-03 23:13:54

标签: c# xml .net-3.5

我想在迭代循环之外改变一个IEEumerable XElement集合(更改属性,子等),它是一个单独的方法。我发现这对引用或赋值是不可能的,因为IEnumerable只返回/产生一个值。

此方法将子节点添加到XElement:

protected static void setErrorOnItem(ref XElement item, DiagErrorCode errorCode, DiagStatus errorLevel) {
    XElement errorNode = new XElement("Error");
        errorNode.SetAttributeValue("errorCode", errorCode.ToString());
        errorNode.SetAttributeValue("errorLevel", errorLevel.ToString());
        item.Element("Errors").Add(errorNode);
    }

除非它位于XElement集合循环的上下文中,否则它将正常工作,该集合由IEnumerable迭代器处理。

可以在循环内设置节点上的属性。但是,如果无法完成引用和赋值,我怎么能把这个逻辑放在它自己的方法中呢?

public IEnumerable<XElement> GetRevisedVariationOverTime(IEnumerable<XElement> items) {
  foreach(XElement item in items) {
    if(sampleSize < RequiredSampleSize) {
      // Works fine...
      item.Attribute("Status").Value = DiagStatus.WARNING.ToString();
      // Can't assign
      item = getItemReplacement(item);
      // Can't reference
      setErrorOnItem(ref item);
    }
  }

  ...
  return items;
}

3 个答案:

答案 0 :(得分:2)

修改集合中的项目应该是安全的,只要您不直接或间接地修改集合本身。您的代码显然打算更改集合中的项目(item = getItemReplacement(item);),因此您当然无法做到这一点。

如果您想用新元素替换当前元素,可以执行以下操作:

public IEnumerable<XElement> GetRevisedVariationOverTime(IEnumerable<XElement> items)
{
    foreach(XElement item in items.ToList()) // note the ToList() call here
    {
        if(sampleSize < RequiredSampleSize)
        {
            item.Attribute("Status").Value = DiagStatus.WARNING.ToString();

            var newItem = getItemReplacement(item);
            setErrorOnItem(ref newItem, ...);

            // do the replacement
            item.Parent.ReplaceWith(newItem);
        }
    }
}

答案 1 :(得分:2)

首先,您的GetRevisedVariationOverTime方法不会像其签名那样返回IEnumerable<XElement>,并且您对setErrorOnItem的使用与其声明不符......所以我'我必须猜测你想要做什么。 (我也看不出item参数需要ref。)

我怀疑你真的想要这样的东西:

public IEnumerable<XElement> GetRevisedVariationOverTime(IEnumerable<XElement> items) {
    foreach(XElement item in items) {
        if(sampleSize < RequiredSampleSize) {
            // Works fine...
            item.Attribute("Status").Value = DiagStatus.WARNING.ToString();

            // yield a replacement item
            yield return getItemReplacement(item);

            // you probably want to do this before you yield the item
            setErrorOnItem(item);
        }
    }
}
然后使用

GetRevisedVariationOverTime来修改这样的序列:

foreach (var item in GetRevisedVariationOverTime(items))
{
   // the items returned are now those yielded by `getItemReplacement`
}

答案 2 :(得分:2)

如果您的方法采用IEnumerable<XElement>并返回相同的值,则可以在迭代时修改序列。例如:

public IEnumerable<XElement> GetRevisedVariationOverTime(IEnumerable<XElement> items)
{
    foreach ( var item in items ) {
        if ( sampleSize < RequiredSampleSize) {
            yield return GetItemReplacement( item );
        }
        else {
            // return item as-is
            yield return item;
        }
    }
}

XElement GetItemReplacement( XElement item )
{
    // modify item in-place and return it, 
    // or create a whole new XElement and return that instead...
}