C# 隐式运算符isn';t调用C中的默认结构#
我正在实现Haskell's Maybe的C#变体,遇到了一个奇怪的问题,C# 隐式运算符isn';t调用C中的默认结构#,c#,implicit-conversion,C#,Implicit Conversion,我正在实现Haskell's Maybe的C#变体,遇到了一个奇怪的问题,null和default对隐式转换返回的值有不同的含义 public class TestClass { public void Test() { Maybe<string> valueDefault = default; Maybe<string> valueNull = null; Maybe<string> value
null
和default
对隐式转换返回的值有不同的含义
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
};
}
}
公共类TestClass
{
公开无效测试()
{
可能valueDefault=默认值;
可能valueNull=null;
可能是valueFoobar=“foobar”;
WriteLine($”Default:(Some{valueDefault.Some},None{valueDefault.None});
WriteLine($“Null:$Some{valueNull.Some},None{valueNull.None}”);
WriteLine($“Foobar:(Some{valueFoobar.Some},None{valueFoobar.None}”);
}
}
可能是公共结构
{
公共T某些{get;私有集;}
公共bool None{get;private set;}
公共静态隐式运算符(T值)
{
返回新的Maybe(){
一些=价值,
无=值==null
};
}
}
输出为:
默认值:(部分,无错误)
Null:(部分,非真)
Foobar:(一些Foobar,没有错误)
我原以为valueDefault
和valueNull
是相等的。但似乎null
被转换了,而default
没有。我用一个反向布尔条件将None替换为HasSome,解决了这个问题,但问题仍然存在
为什么null和default的处理方式不同?default
总是用零字节填充结构的内存。null
不是值类型的有效值,因此编译器会发现隐式的(可能)(字符串)null
强制转换
也许你可以用
公共结构
{
公共T某些{get;私有集;}
公共bool None=>Some==null;
...
每种类型都有一个默认值,包括可能
。有关列表,请参阅
Maybe-valueDefault=default;
将Maybe
的默认值分配给valueDefault
。Maybe
的默认值是什么?根据该页面,由于Maybe
是一个结构,其默认值是:
通过将所有值类型字段设置为其默认值并将所有引用类型字段设置为null而生成的值
因此,它是的一个实例,可能的部分为null
,无为false
,false
是bool
的默认值
编译器不会尝试使用默认值string
,因为这需要进一步转换到Maybe
。如果它可以使用默认值Maybe
,为什么还要额外麻烦呢
您可以强制它执行以下操作:
Maybe<string> valueDefault = default(string);
Maybe valueDefault=default(字符串);
另一方面,null
被转换为Maybe
,因为null
不是Maybe
的有效值(structs不能为null!),因此编译器推断您的意思必须是null as string
,并进行隐式转换
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
};
}
}
您可能已经知道这一点,但您似乎正在重新设计@JeremyLakeman right,因为引用类型可以是null
。由编译器将null作为字符串推导为null是非常有意义的。但是null
不符合我的目的,因为我非常希望在结构内部强制null验证n通过选项
的方式,可以潜在地防止消费者抛出NullReferenceException
。这对于可能
之类的值类型不是很有用,因为您永远无法将其设置为无
等于真
的值。对于将来的参考,您可能通过调试代码并查看隐式运算符在Maybe valueDefault=default;
@devNull:从问题的标题判断,我认为OP可能理解“隐式运算符实际上没有被调用”?我承认,这很难说。当然,如果他们真的理解了这一点,那么他们为什么会对默认值的含义感到惊讶也不清楚。我发现很难确切地说出OP无法理解的部分。希望评论和回答中有足够的信息,让他们得到他们想要的,不管是什么。@PeterDuniho True,我试图找到一种方法来强制default
调用隐式运算符。而我应该在结构中设置适当的默认值None
。