C#中实现可空类型转换运算符时出现错误

3
我目前正在创建一个struct Nullsafe<T>,它将包装引用类型(因此T:class),并以类似于Nullable<T> struct的方式运行。这样做的目的是模拟类似于F#中Option<T>的功能。
我打算在需要特别处理null的方法中使用该类型。例如,假设我有一个引用类型class Foo,并且以下代码:
class Bar
{
    public void DoSomethingWithFoo(Nullsafe<Foo> foo);
}

自从我创建了一个从TNullsafe<T>的隐式转换运算符,那么下面的代码就可以正常工作:
Bar bar = new Bar();

Foo nullFoo = null;
bar.DoSomethingWithFoo(nullFoo);

Foo someFoo = new Foo();
bar.DoSomethingWithFoo(someFoo);
Nullsafe<T> 类型是一个结构体(特意设计为这样,以消除直接传递任何 null 值的可能性),因此有人可以编写以下代码片段:
Nullable<Nullsafe<Foo>> nullableNullsafeFoo = null;
// and later
bar.DoSomethingWithFoo(nullableNullsafeFoo);

明显,这个片段是行不通的。

因此,我认为从我的 Nullsafe<T> 结构中创建一个类型转换运算符应该是易如反掌的,它可以处理像上面那样的可空表达式:

public static implicit operator Nullsafe<T>(Nullable<Nullsafe<T>> nv) => nv.GetValueOrDefault();

很遗憾,编译失败。编译器似乎无法区分 Nullsafe<T> 和 Nullable<Nullsafe<T>> 类型,并向我抛出以下消息:
以上是编译器的限制还是故意的行为?如果是这样,是否有任何已知的解决方法?
错误代码如下:
error CS0555: 用户定义的运算符不能将封闭类型的对象转换为封闭类型的对象
我正在使用:
Visual Studio Community 2017 v15.8.1
.NET Sdk v2.1.400 (通过 dotnet --version 显示)
该项目是一个库,支持不同的 .NET 框架版本 - 从 net20 到 netstandard2.0。
更新:
以上是编译器的限制还是故意的行为?

看起来这确实是编译器剥离类型信息的结果,正如用户Isaac van Bakel所描述的那样。

如果是这样,是否有已知的解决方法?

按照他的建议,我向roslyn平台提交了一个问题

2个回答

1
这是否是有意为之尚不清楚,基于 Roslyn 中的代码。该行为来自于编译器从类型转换中剥离 Nullable 包装器以正确捕获从 Nullable<Foo>Nullable<Foo> 的相等转换 - 但在您的情况下,在剥离之前类型是不同的,因此应该是允许的。
您可以在 存储库 中开启一个问题 - 我找不到已经开放的问题。熟悉编译器设计的人将能够参与讨论,但似乎确实存在一个错误。

感谢您的反馈,很高兴知道这种行为似乎并不是有意的。我已按照您的建议提交了一个问题,并更新了问题描述。 - Ivaylo Slavov

0

实际上,观察到的行为是有意的并得到确认

创建了一个语言设计讨论线程,以解决是否应该改变这种行为,以支持类似上述用例,或者提供更好的编译器错误消息以显示。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接