捕获 foreach 循环中的行为 C#

发布于 2024-12-04 08:24:49 字数 270 浏览 1 评论 0原文

简单的问题,我相信-->据我了解,当我在 IEnumerable 对象上使用 foreach 循环时,正在使用虚构的 IEnumerator 对象。我的问题如下:

如何“捕获”处理我的对象的 foreach 循环中的非法行为?我特别想查看创建 IEnumerable 的原始对象是否已被修改。如果原来的被修改了,我想抛出异常。

我目前的方法是使用版本号。如果我创建一个显式迭代器并使用 MoveNext() 或类似的东西,这会非常有效,但 foreach 循环似乎欺骗了我基于版本的方法。

Simple question, I believe --> It is my understanding that an imaginary IEnumerator object is being used when I use a foreach loop over an IEnumerable object. My question is as follows:

How can I "catch" illegal behavior in foreach loops dealing with my objects? I specifically want to see if my original object from which the IEnumerable was created has been modified. If the original has been modified, I want to throw an exception.

My current approach has been to use a version number. This works great if I create an explicit iterator and use a MoveNext() or somesuch, but foreach loops seem to trick my version-based approach.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

南汐寒笙箫 2024-12-11 08:24:49

值得注意的是,vb.net 或 c# 中的 foreach 循环将鸭式类型化 GetEnumerator 方法,该方法返回一个对象,并带有返回布尔值的 MoveNext 方法和返回合适类型的 Current 属性。尽管 GetEnumerator() 方法通常是 IEnumerable.GetEnumerator() 的实现,但并非必须如此。在某些情况下,如果 GetEnumerator() 返回值类型而不是类类型或装箱的 IEnumerable,性能可能会更好。因此,可以在实现 IEnumerable的对象上调用 foreach 循环。与将对象强制转换为 IEnumerable相比,将使用不同的语义。第一的,。

It's worthwhile to note that a foreach loop in vb.net or c# will duck-type a GetEnumerator method that returns an object with a MoveNext method that returns Boolean and a Current property that returns a suitable type. Although the GetEnumerator() method will usually be an implementation of IEnumerable<T>.GetEnumerator(), it doesn't have to be. In some cases, performance may be better if GetEnumerator() returns a value type rather than a class-type or boxed IEnumerable<T>. It's thus possible that invoking a foreach loop on an object which implements IEnumerable<T> will use different semantics than if the object were cast to IEnumerable<T> first,.

一桥轻雨一伞开 2024-12-11 08:24:49

IEnumerable 接口实际上返回 IEnumerator,这是该接口存在的全部原因。

当调用 foreach 块时,将调用 IEnumerable.GetEnumerator() 方法来获取枚举数。

如果您想跟踪每个项目,那么因为它们是对象类型,所以它们将被引用,因此您将获得最新版本的更新。在该项目中,您可以像这样实现您提到的版本控制。

public class SomeItem
{
  private string _Value;
  private int _Version = 0;
  private int _LastKnown = 0;

  public SomeItem()
  {

  }

  public SomeItem(string value)
  {
     this._Value = value
  }


  public string Value
  {
     get { return this._Value; }
     set { if (this._Value != value) { this._Value = value; this._Version++; } }
  }

  public int Version
  {
    get { return this._Version; }
  }

  public bool HasChanged
  {
     get { return (this._Version != _LastKnown); }
  }

 // Reset change tracking.
 public void Reset()
 {
    this._LastKnown = this._Version;
 }
}

在其他地方,您可以在循环中使用类似的东西。

private List<SomeItem> _Items = new List<SomeItem>();

// Add an item.
_Items.Add(new SomeItem("ABC"));

// Add a changed item.
SomeItem itemN = new SomeItem("EFG");
itemN.Value = "XYZ";
_Items.Add(itemN);


foreach (SomeItem item in _Items)
{
   if (item.HasChanged)
   {
      // Do stuff here.
      //throw new Exception()
   }
}

更新

或者,如果您只是想了解哪些项目已更改,您可以执行类似的操作。

SomeItem[] changedItems = _Items.Where(item => item.HasChanged);

根据 dlev 的建议,如果您只想知道是否有任何更改,请使用。

if (_Items.Any(item => item.HasChanged))
{
   // An item has changed, do stuff.
}

The IEnumerable interface is what actualy returns the IEnumerator it is the whole reason this interface exists.

When the foreach block is call the IEnumerable.GetEnumerator() method is called to get the enumerator.

If you want to track each item then because they are object types they will be referenced so you will have the update to date version. Within the item you could implement the versioning that you mentioned like so.

public class SomeItem
{
  private string _Value;
  private int _Version = 0;
  private int _LastKnown = 0;

  public SomeItem()
  {

  }

  public SomeItem(string value)
  {
     this._Value = value
  }


  public string Value
  {
     get { return this._Value; }
     set { if (this._Value != value) { this._Value = value; this._Version++; } }
  }

  public int Version
  {
    get { return this._Version; }
  }

  public bool HasChanged
  {
     get { return (this._Version != _LastKnown); }
  }

 // Reset change tracking.
 public void Reset()
 {
    this._LastKnown = this._Version;
 }
}

Elsewhere you could use something like this in your loop.

private List<SomeItem> _Items = new List<SomeItem>();

// Add an item.
_Items.Add(new SomeItem("ABC"));

// Add a changed item.
SomeItem itemN = new SomeItem("EFG");
itemN.Value = "XYZ";
_Items.Add(itemN);


foreach (SomeItem item in _Items)
{
   if (item.HasChanged)
   {
      // Do stuff here.
      //throw new Exception()
   }
}

UPDATED

Alternatively if you just want to find out what items have changed you could do something like this.

SomeItem[] changedItems = _Items.Where(item => item.HasChanged);

As per dlev's suggestion if you just want to know if any changed just use.

if (_Items.Any(item => item.HasChanged))
{
   // An item has changed, do stuff.
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文