尝试在 C# 中将转换运算符实现为可空类型时出错

Error when trying to implement cast operator to nullable type in C#

我目前正在创建一个 struct Nullsafe<T>,它将包装一个引用类型(因此 T:class)并且其行为方式与 Nullable<T> struct 类似。重点是模拟 F# 中 Option<T> 所做的事情。

我打算在需要特别注意空值的方法中使用该类型。例如,假设我有一个引用类型 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: User-defined operator cannot take an object of the enclosing type and convert to an object of the enclosing type

我正在使用:

该项目是一个库,针对不同的 .NET 框架版本 - 从 net20 到 netstandard2.0

更新

Is the above a limitation of the compiler, or is it a purposedly intended behaviour?

这似乎确实是编译器剥离类型信息的结果,正如其他用户所述Isaac van Bakel

If so, are there any known workarounds?

按照他的建议,我提交了an issue到roslyn平台。

根据 Roslyn 中的代码,尚不清楚这是否确实有意为之。该行为来自编译器从转换中涉及的类型中剥离 Nullable 包装器,以便正确捕获从 Nullable<Foo>Nullable<Foo> 的身份转换 - 但在您的情况下,类型之前不同剥离,所以应该允许。

您可以在 the repository 中打开一个问题 - 我找不到任何已经打开的问题。更熟悉编译器设计的人可以权衡一下,但这确实像是一个错误。

观察到的行为实际上是 and confirmed

已创建语言设计 discussion thread,以解决是否应更改此行为以支持上述用例,或者以其他方式提供更好的编译器错误消息显示。