C# 中的默认结构不调用隐式运算符
Implicit operator isn't called for default of struct in C#
我正在实现 Haskell 的 Maybe 的 C# 变体并遇到一个奇怪的问题,其中 null
和 default
对从 [= 返回的值有不同的含义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)
我原以为 valueDefault
和 valueNull
是相等的。但似乎 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>
赋值给 valueDefault
。 Maybe<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>
的一个实例,其中 Some
是 null
,None
是 false
。 false
是bool
的默认值。
编译器不会尝试使用默认值 string
,因为这需要进一步转换为 Maybe<string>
。如果可以直接使用默认值Maybe<string>
,何必多此一举,对吧?
你可以强制它:
Maybe<string> valueDefault = default(string);
另一方面,null
被转换为 Maybe<string>
,因为 null
不是 Maybe<string>
的有效值(结构不能为空!) ,因此编译器推断出您的意思一定是 null as string
,并进行隐式转换。
您可能已经知道这一点,但您似乎正在重新发明 Nullable<T>
我正在实现 Haskell 的 Maybe 的 C# 变体并遇到一个奇怪的问题,其中 null
和 default
对从 [= 返回的值有不同的含义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)
我原以为 valueDefault
和 valueNull
是相等的。但似乎 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>
赋值给 valueDefault
。 Maybe<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>
的一个实例,其中 Some
是 null
,None
是 false
。 false
是bool
的默认值。
编译器不会尝试使用默认值 string
,因为这需要进一步转换为 Maybe<string>
。如果可以直接使用默认值Maybe<string>
,何必多此一举,对吧?
你可以强制它:
Maybe<string> valueDefault = default(string);
另一方面,null
被转换为 Maybe<string>
,因为 null
不是 Maybe<string>
的有效值(结构不能为空!) ,因此编译器推断出您的意思一定是 null as string
,并进行隐式转换。
您可能已经知道这一点,但您似乎正在重新发明 Nullable<T>