#c# #implicit-conversion
#c# #неявное преобразование
Вопрос:
Я реализую C # вариант Maybe от Haskell и столкнулся со странной проблемой, когда null
и default
имеет разные последствия для значения, возвращаемого из implicit
преобразования.
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
};
}
}
Вывод, являющийся:
По умолчанию: (Some , None False)
Null: (Some , None True)
Foobar: (Некоторый foobar, ни один False)
Я ожидал, что оба valueDefault
и valueNull
будут равны. Но кажется, что null
это преобразуется, пока default
это не так. Я исправил проблему, заменив None на HasSome с обратным логическим условием, но все же вопрос остается.
Почему null и default обрабатываются по-разному?
Комментарии:
1. Это не будет очень полезно для типов значений, таких как
Maybe<int>
, поскольку вы никогда не сможете установить для него значение,None
равноеtrue
.2. Для дальнейшего использования вы, вероятно, найдете ответ, отладив код и увидев, что неявный оператор фактически не вызывается в
Maybe<string> valueDefault = defau<
3. @devNull: судя по названию вопроса, я думаю, может быть, OP понимает, что «неявный оператор на самом деле не вызывается» ? Признаюсь, трудно сказать. И, конечно, если они это понимают, непонятно, почему они удивлены значением
default
. Мне трудно точно сказать, какую часть всего этого OP не понимает. Надеюсь, в комментариях и ответах достаточно информации, чтобы они получили то, что хотят, что бы это ни было.4. @PeterDuniho Верно, я пытался найти способ принудительно
default
вызвать неявный оператор. В то время как я вместо этого должен установить соответствующее значение по умолчаниюNone
внутри структуры.
Ответ №1:
Каждый тип имеет значение по умолчанию, в том числе Maybe<T>
. Список см. На этой странице.
Maybe<string> valueDefault = defau<
присвоит значение по умолчанию Maybe<string>
to valueDefault
. Какое значение по умолчанию Maybe<string>
? Согласно этой странице, поскольку Maybe<string>
это структура, ее значение по умолчанию равно:
Значение, полученное путем установки для всех полей типа значения их значений по умолчанию и для всех полей ссылочного типа значения null.
Так что это экземпляр Maybe<string>
with Some
being null
и None
being false
. false
является значением по умолчанию bool
.
Компилятор не пытается использовать значение по умолчанию string
, поскольку для этого требуется дальнейшее преобразование в Maybe<string>
. Если он может просто использовать значение по умолчанию Maybe<string>
, зачем лишние проблемы, верно?
Вы можете заставить его, хотя:
Maybe<string> valueDefault = default(string);
null
с другой стороны, преобразуется в Maybe<string>
because null
не является допустимым значением Maybe<string>
(structs не может быть null!), Поэтому компилятор выводит, что вы должны иметь в виду null as string
, и выполняет неявное преобразование.
Возможно, вы уже знаете это, но, похоже, вы изобретаете Nullable<T>
Комментарии:
1. @JeremyLakeman прав, потому что ссылочные типы могут быть просто
null
.2. Имеет смысл, null выводится
null as string
компилятором. ОднакоNullable<T>
это не соответствовало бы моей цели, поскольку я хочу принудительно выполнить проверку null внутри struct во многом так, как этоOption<T>
делается в language-ext , что потенциально предотвращаетNullReferenceException
выброс потребителем.
Ответ №2:
default
всегда заполняет память структуры нулевыми байтами. null
недопустимое значение для типа значения, поэтому компилятор обнаруживает неявное (Maybe<string>)(string)null
приведение.
Возможно, вы могли бы заменить на;
public struct Maybe<T>
{
public T Some { get; private set; }
public bool None => Some == null;
...