C 言語ファミリをルーツとし、コンポーネント指向プログラミングのサポートを含む、オブジェクト指向およびタイプセーフのプログラミング言語。
おそらくの勘違いのもととして、C/C++系列の比較の場合を知っているためだろう誤解だと思います。
C/C++ではnullは数値0とみなして比較をおこないます。
-
null==0は0==0と同じであり、真となります。 -
null!=0は0!=0と同じであり、偽となります。
if(null != 0)
{
ここは処理されない
}
int x = null + 2; // x は2になる (nullを数値の0で四則演算するから)
しかしC#のnullは数値の0でなく、参照型(クラス)において何も参照していないという意味をあらわすためです。
null キーワードは、null 参照を表すリテラルであり、どのオブジェクトも参照しません。 null は参照型変数の既定値です。 null 許容値型を除き、通常の 値型を null にすることはできません。
そして、数値の0というのは値型です。
値型と参照型というのは違う型であることは自明であるため、それが等価であるかの演算である等価演算子==では偽になります。その逆である非等価演算子!=では真になります
参照型 == 値型 ⇒ 偽
参照型 != 値型 ⇒ 真
よって
null != 0 ⇒ 真
int? x = null + 2; // xはnullになる。( nullを四則演算につかうとnullになるという言語仕様)
つまりlist?.Countがnullでは参照型nullと価型の0との非等価演算になって、結果は真となります。
等値演算子の説明で値型の等価性と参照型の等価性についてで書かれてることなのですが、nullと値型との比較についてはわかりにくい説明ですね。(C#のLanguage Specificationでもわかりにくいです)
結局はC#のnullは値ではないという言語仕様によってこうなっているのです。
ですから他言語では違うこともあるので、当たり前とはちょっとちがうかなと思います。