拡張メソッドを null に対して呼び出すと...

以前の記事で 拡張メソッドについて説明しました。

拡張メソッドはスタティックメソッドでありながら、変数に対して . (ドット) を使って、すなわちインスタンスメソッドのように呼び出すことが可能です。

では、null がセットされている変数 (オブジェクト) に対して拡張メソッドを呼び出すとどうなるでしょうか。

念のために実験して動作確認しておきましょう。

拡張メソッドは null に対しても安全

それでは実験のために次のような、string 型に対する拡張メソッドを用意します。

using System;

namespace MyTest
{
	public static class Extensions
	{
		public static void Print(this string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				Console.WriteLine("(null)");
			}
			else
			{
				Console.WriteLine("{0}", s);
			}
		}
	}
}

string に対する拡張で、コンソールに string を出力します。

ここでこの拡張メソッドを、次のプログラムで実験します。

namespace MyTest
{
	class Program
	{
		static void Main(string[] args)
		{
			string s1 = "Hello";
			s1.Print();

			string s2 = null;
			s2.Print();

			string s3 = null;
			s3.ToString();
		}
	}
}

ここでは string として s1, s2, s3 をそれぞれ用意し、s1 には "Hello" という文字列で初期化、s2, s3 には null で初期化します。

s1, s2 は拡張メソッドである Print() を呼び出し、s3 はインスタンスメソッドとして ToString() を呼び出します。

この結果は次のようになりました。

Hello
(null)

Unhandled Exception: System.NullReferenceException: 
Object reference not set to an instance of an object.
   at MyTest.Program.Main(String[] args) in C:\...

インスタンスメソッドは、null に対して呼び出せば当然ながら NullReferenceException が発生する。 しかし、拡張メソッドは null に対しても安全に呼び出せる、ということが確認できました。

念のため IL コードもみておきます。

ILDasm で IL を覗くと、次のようになります。

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       33 (0x21)
  .maxstack  1
  .locals init ([0] string s1,
           [1] string s2,
           [2] string s3)
  IL_0000:  nop
  IL_0001:  ldstr      "Hello"
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  call void MyTest.Extensions::Print(string)
  IL_000d:  nop
  IL_000e:  ldnull
  IL_000f:  stloc.1
  IL_0010:  ldloc.1
  IL_0011:  call void MyTest.Extensions::Print(string)
  IL_0016:  nop
  IL_0017:  ldnull
  IL_0018:  stloc.2
  IL_0019:  ldloc.2
  IL_001a:  callvirt instance string [mscorlib]System.Object::ToString()
  IL_001f:  pop
  IL_0020:  ret
} // end of method Program::Main

つまり拡張メソッドはドット形式ではありますが、内部でスタティックメソッドの呼び出しに展開されています。

このために null に対しても問題なく呼び出せるわけです。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 C# 入門