Я сталкивался с этим, и мне любопытно, почему невозможно использовать оператор is
для различения между bool
и Nullable<bool>
? Пример;
void Main()
{
bool theBool = false;
Nullable<bool> theNullableBoolThatsFalse = false;
Nullable<bool> theNullableBoolThatsNull = null;
void WhatIsIt(object value)
{
if(value is bool)
Console.WriteLine(" It's a bool!");
if(value is Nullable<bool>)
Console.WriteLine(" It's a Nullable<bool>!");
if(value is null)
Console.WriteLine(" It's a null!");
}
Console.WriteLine("Considering theBool:");
WhatIsIt(theBool);
Console.WriteLine("Considering theNullableBoolThatsFalse:");
WhatIsIt(theNullableBoolThatsFalse);
Console.WriteLine("Considering theNullableBoolThatsNull:");
WhatIsIt(theNullableBoolThatsNull);
}
Звонит Main()
дает;
Considering theBool:
It's a bool!
It's a Nullable<bool>!
Considering theNullableBoolThatsFalse:
It's a bool!
It's a Nullable<bool>!
Considering theNullableBoolThatsNull:
It's a null!
Я бы ожидал;
Considering theBool:
It's a bool!
Considering theNullableBoolThatsFalse:
It's a Nullable<bool>!
Considering theNullableBoolThatsNull:
It's a null!
Почему оба bool
и Nullable<bool>
соответствуют друг другу?
Что я пробовал;
- Я ознакомился с документами по
Nullable
, is
, switch
и сопоставлению с образцом.
- Я думаю, это может быть связано с распаковкой значения, когда оно передается в метод?
Я думаю, что это может быть уникально для Nullable
, потому что я не сталкиваюсь с такими же проблемами для других универсальных типов. Например;
void Main()
{
bool theBool = false;
List<bool> theListOfBool= new List<bool>();
void WhatIsIt(object value)
{
if(value is bool)
Console.WriteLine(" It's a bool!");
if(value is List<bool>)
Console.WriteLine(" It's a List<bool>!");
}
Console.WriteLine("Considering theBool:");
WhatIsIt(theBool);
Console.WriteLine("Considering theListOfBool:");
WhatIsIt(theListOfBool);
}
Придает;
Considering theBool:
It's a bool!
Considering theListOfBool:
It's a List<bool>
Я не пытаюсь решить проблему. Просто интересно, почему так работает.
Ответы до сих пор предполагают, что именно преобразования implicit
и explicit
вызывают такое поведение, но я не смог выполнить репликацию в следующем примере;
class A
{
public static implicit operator A(B value) => new A();
public static explicit operator B(A value) => new B();
}
class B
{
public static implicit operator A(B value) => new A();
public static explicit operator B(A value) => new B();
}
static void Main(string[] args)
{
var a = new A();
var b = new B();
void WhatIsIt(object value)
{
if (value is A)
Console.WriteLine(" It's a A!");
if (value is B)
Console.WriteLine(" It's a B!");
}
Console.WriteLine("Considering a;");
WhatIsIt(a);
Console.WriteLine("Considering b;");
WhatIsIt(b);
}
Придает;
Considering a;
It's a A!
Considering b;
It's a B!
Документы для is
говорят:
Он рассматривает только ссылочные преобразования, преобразования в блокировку и преобразования в распаковку; он не учитывает пользовательские преобразования или преобразования, определенные неявными и явными операторами типа. В следующем примере генерируются предупреждения, потому что результат преобразования известен во время компиляции. Обратите внимание, что это выражение для преобразований из int в long и double возвращают false, поскольку эти преобразования обрабатываются неявным оператором.
Решения, которые решает фреймворк, - ссылочные преобразования, преобразования в боксы и распаковки?