C# 中的默认结构不调用隐式运算符

Implicit operator isn't called for default of struct in C#

我正在实现 Haskell 的 Maybe 的 C# 变体并遇到一个奇怪的问题,其中 nulldefault 对从 [= 返回的值有不同的含义13=]转换。

public class TestClass
{
    public void Test()
    {
        Maybe<string> valueDefault = default;
        Maybe<string> valueNull = null;
        Maybe<string> valueFoobar = "foobar";
        Console.WriteLine($"Default: (Some {valueDefault.Some}, None {valueDefault.None}");
        Console.WriteLine($"Null: (Some {valueNull.Some}, None {valueNull.None}");
        Console.WriteLine($"Foobar: (Some {valueFoobar.Some}, None {valueFoobar.None}");
    }
}

public struct Maybe<T>
{
    public T Some { get; private set; }
    public bool None { get; private set; }

    public static implicit operator Maybe<T>(T value)
    {
        return new Maybe<T>() {
            Some = value,
            None = value == null
        };
    }
}

输出为:

Default: (Some , None False)

Null: (Some , None True)

Foobar: (Some foobar, None False)

我原以为 valueDefaultvalueNull 是相等的。但似乎 null 已转换,而 default 未转换。我通过将 None 替换为具有反向布尔条件的 HasSome 来解决问题,但问题仍然存在。

为什么 null 和 default 的处理方式不同?

default 总是 用零字节填充结构的内存。 null 不是值类型的有效值,因此编译器发现隐式 (Maybe<string>)(string)null 强制转换。

也许你可以替换为;

public struct Maybe<T>
{
    public T Some { get; private set; }
    public bool None => Some == null;
...

每个类型都有一个默认值,包括Maybe<T>。有关列表,请参阅 this page

Maybe<string> valueDefault = default; 会将默认值 Maybe<string> 赋值给 valueDefaultMaybe<string> 的默认值是多少?根据该页面,由于 Maybe<string> 是一个结构,因此其默认值为:

The value produced by setting all value-type fields to their default values and all reference-type fields to null.

所以它是 Maybe<string> 的一个实例,其中 SomenullNonefalsefalsebool的默认值。

编译器不会尝试使用默认值 string,因为这需要进一步转换为 Maybe<string>。如果可以直接使用默认值Maybe<string>,何必多此一举,对吧?

你可以强制它:

Maybe<string> valueDefault = default(string);
另一方面,

null 被转换为 Maybe<string>,因为 null 不是 Maybe<string> 的有效值(结构不能为空!) ,因此编译器推断出您的意思一定是 null as string,并进行隐式转换。


您可能已经知道这一点,但您似乎正在重新发明 Nullable<T>