如何为实现 IEnumerable 的 class 创建解构函数

How to make a Deconstructor for class that implements IEnumerable

我有一个 class 实现了 IEnumerable。它包含一个 GetEnumerator() 方法和一个实现 IEnumerator 的私有 class。 class return 的 Current() 方法是一个 KeyValuePair 对象,即(为清楚起见省略了一些代码)

internal sealed class BlockSheet : IEnumerable
{
    public IEnumerator GetEnumerator ()
    {
        return new BlockSheetEnumerator (this);
    }

    private class BlockSheetEnumerator : IEnumerator
    {
        public object Current
        {
            get
            {
                KeyValuePair<Point, Actor> pair = (KeyValuePair<Point, Actor>)this.enumerator.Current;
                return pair;
            }
        }
    }
}

如果我按如下方式调用,效果很好

foreach (KeyValuePair<Point, Actor> unit in blocksheet)

但如果我尝试使用隐式 KeyValuePair 解构器并编写

foreach ((Point coordinate, Actor actor) in blocksheet)

然后我得到两个错误:

错误 CS1061:'object' 不包含 'Deconstruct' 的定义并且没有可访问的扩展方法 'Deconstruct' 接受类型 'object' 的第一个参数可以找到(您是否缺少 using 指令或程序集引用?)(CS1061)

错误 CS8129:没有为类型 'object' 找到合适的 'Deconstruct' 实例或扩展方法,具有 2 个输出参数和一个 void return 类型。 (CS8129)

(这与例如 的错误相同,但我认为这不适用 - 见下文)

我本以为我会得到解构器'for free'。我已经尝试向 BlockSheet class 和 BlockSheetEnumerator class 添加 Deconstruct 方法,但没有效果(我觉得这没有意义,因为 class 都不是被解构)。

我的目标是使用 C# 9 的 .NET 5,使用 Visual Studio 2019 作为 Mac 版本 8.10.22(内部版本 11)。当然,我已经成功地使用了一个带有字典对象的解构器,向我自己证明这与语言/.NET 版本无关。

IEnumerable 表示“Object 的集合”。所以,在循环中你在每次迭代中得到一个 object 并且你实际上尝试解构对象,而不是 KeyValuePair<TKey, TValue>。而且您没有适合 object.

的解构函数

要使用解构,您需要明确和具体的类型。为此,您可以:

  • 为您的对象 BlockSheet 实施 IEnumerable<KeyValuePair<Point, Actor>>/IEnumerator<KeyValuePair<Point, Actor>>。顺便说一句,实现通用 IEnumerable<T> 后,您可以通过通用 non-generic IEnumerable 轻松实现

  • 只需使用强制转换 foreach (var (key,val) in blocksheet.Cast<KeyValuePair<Point, Actor>>()){/*loop body*/}。但这对我来说似乎不是最佳选择。

  • 你也可以为 Object 实现 Deconstruct,但你应该弄清楚它应该如何为对象表现,而不是想要的 KeyValuePair,所以我强烈不推荐这种方式

      public static class Ext
      {
          public static void Deconstruct(this Object obj, out Point a, out Actor b)
          {
              if(obj is KeyValuePair<Point, Actor> pair)
              {
                  (a,b)=pair;
              }
              else
              {
                  a=null;
                  b=null;
                  // what can we do here?
              }
          }
      }