如何为实现 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?
}
}
}
我有一个 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-genericIEnumerable
轻松实现只需使用强制转换
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? } } }