【C#】nullableの挙動を確認する

int? nullable;
int nonNullable;

とりあえずこんな感じの変数を使います

代入

nonNullable = 10;
nullable = nonNullable;

nullable = 20;
nonNullable = nullable;  //←コンパイルエラー
nonNullable = (int)nullable;

nullable = null;
nonNullable = (int) nullable;  //←System.InvalidOperationException

null非許容型からnull許容型への代入:問題なし
null許容型からnull非許容型への代入:キャストが必要
みたいですね ちなみにnull許容型からnull非許容型へのキャスト時にはちゃんと値が入ってないとExceptionでるのでちゃんとnullチェックするとか??演算子使うとかしましょう

関数

オーバロード

static void Func(int? arg)
{
    Console.WriteLine("Func-nullable");
}

static void Func(int arg)
{
    Console.WriteLine("Func-nonNullable");
}

こんな感じの関数の定義は問題なくできました

実際にこの関数を呼んだ時の動作ですが

nullable = nonNullable = 10;
Func(nullable);             //Func-nullable
Func(nonNullable);          //Func-nonNullable
Func((int?)nonNullable);    //Func-nullable
Func((int)nullable);        //Func-nonNullable

コメントで記述しているように、int?型とint型は別の型と認識されて関数が呼ばれています
キャストすれば型が変わったものと認識されるようです(当たり前か)

別の関数は呼べるのか

関数定義を変更しました

static void Func_Nullable(int? arg)
{
    Console.WriteLine("Func_Nullable");
}

static void Func_NonNullable(int arg)
{
    Console.WriteLine("Func_NonNullable");
}

そして呼び出し側ですが

nullable = nonNullable = 10;
Func_Nullable(nonNullable);
Func_NonNullable(nullable);  //←コンパイルエラー

nullable型の関数にnonNullableを渡すのは問題ないようです
ただ逆はエラーですね キャストしましょう

拡張関数

オーバロード

static class Extensions
{
    public static void ExFunc(this int? arg)
    {
        Console.WriteLine("ExFunc-nullable");
    }

    public static void ExFunc(this int arg)
    {
        Console.WriteLine("ExFunc-nonNullable");
    }
}

定義は問題なくできました
そしてこれを呼び出します

nullable = nonNullable = 10;
nullable.ExFunc();              //ExFunc-nullable
nonNullable.ExFunc();           //ExFunc-nonNullable
((int?)nonNullable).ExFunc();   //ExFunc-nullable
((int)nullable).ExFunc();       //ExFunc-nonNullable
nullable?.ExFunc();             //ExFunc-nonNullable ☆

nullable = null;
nullable.ExFunc();              //ExFunc-nullable
nullable?.ExFunc();             //←関数が呼ばれない   ☆

注目すべきは☆マークのある2つですね nullablenullでないときはint型の関数が呼ばれ、nullのときは関数が呼び出されません この動作は拡張関数でも使えるようです

まとめ

  • キャストすればなんとかなる
  • null許容型変数?.関数名()の構文は拡張関数でも使える

(実は確認したかったのは拡張関数の挙動だけだったりする)

以上