gpt4 book ai didi

c# - .NET 实现具有可空引用类型的 IEnumerator

转载 作者:行者123 更新时间:2023-11-30 21:27:02 25 4
gpt4 key购买 nike

release of C# 8.0 ,我真的很享受 nullable reference types 带来的“虚空安全” .然而,在调整我的库以支持新功能时,我偶然发现了一个我真的无法在任何地方找到答案的“问题”。我查看了 Microsoft 的发行说明和 .NET 源代码,但没有成功。

TL;DR:问题本质上是一个 IEnumerator<T> 是否存在的 Current属性应声明为可为 null 的引用类型。

假设 IEnumerator<T> 的以下实现:

public class WebSocketClientEnumerator<TWebSocketClient> : IEnumerator<TWebSocketClient> where TWebSocketClient : WebSocketClient
{
private WebSocketRoom<TWebSocketClient> room;
private int curIndex;
private TWebSocketClient? curCli;

public WebSocketClientEnumerator(WebSocketRoom<TWebSocketClient> room)
{
this.room = room;
curIndex = -1;
curCli = default(TWebSocketClient);
}

public bool MoveNext()
{
if (++curIndex >= room.Count)
{
return false;
}
else
{
curCli = room[curIndex];
}

return true;
}

public void Reset() { curIndex = -1; }

void IDisposable.Dispose() { }

public TWebSocketClient? Current
{
get { return curCli; }
}

object IEnumerator.Current
{
get { return Current; }
}
}

并假设以下代码使用枚举器:

public class WebSocketRoom<TWebSocketClient> : ICollection<TWebSocketClient> where TWebSocketClient : WebSocketClient
{
// ...

public void UseEnumerator()
{
var e = new WebSocketClientEnumerator<TWebSocketClient>(this);
bool hasNext = e.MoveNext();
if (hasNext)
{
WebSocketClient c = e.Current; // <= Warning on this line
}
}

// ...
}

按原样,代码将生成警告,因为很明显,WebSocketClientEnumerator<TWebSocketClient>.Current 的返回类型是可为空的引用类型。

IEnumerator界面的设计方式让人“应该”调用 IEnumerator<T>.MoveNext()预先知道枚举数是否有下一个值的方法,从而实现某种无效安全,但显然,在编译器看来,这没有任何意义,调用 MoveNext()方法并不能本质上保证枚举器的 Current属性不为空。

我希望我的库在没有警告的情况下编译,编译器不会让我离开 this.curClinull如果它未声明为可空引用类型,则构造函数中的值,如果它被声明为可空,则检查空引用的“负担”将转移到库的客户端。当然,枚举器通常通过 foreach 消耗语句,因此它主要由运行时处理,可能没什么大不了的。确实,从语义上讲,它对于枚举器的 Current 是有意义的属性为null因为可能没有数据可枚举,但我确实看到 IEnumerator<T> 之间存在冲突接口(interface)和可为空的引用类型特性。我真的很想知道是否有办法在保持功能的同时让编译器满意。此外,其他一些具有无效安全机制的语言的约定是什么?

我意识到这是一个开放式问题,但我仍然认为它适合 SO。提前致谢!

最佳答案

我肯定会建议将其声明为非空版本。 documentation for Current指出行为是在 curCli 实际上为 null 的情况下定义的。我认为在那些情况下阅读 Current 的任何人在他们的代码中都有一个错误,最好通过异常来显示该错误......这真的很容易做到:

public TWebSocketClient Current => curCli ??
throw new InvalidOperationException("Current should not be used in the current state");

当返回 false 时,您可能还想将 curCli 设置为 null,这样如果代码访问 Current 枚举器用尽后。

在这一点上,我认为您的代码比编译器为 yield return 生成的代码更好,后者不会抛出异常。

关于c# - .NET 实现具有可空引用类型的 IEnumerator,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58372075/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com