rksoftware

Visual Studio とか C# とかが好きです

C# のオーバーロードの確認 (継承の親子関係の型の引数)

多くのプログラミング言語に、メソッドのオーバーロードという機能があります。当然 C# にもあります。

今回はそんなオーバーロードについて、そうだろうと思いつつ試していなかったことを試していきたいと思います。

■ まずはオーバーロードとは

メソッドの引数が違えば、別のメソッドに同じ名前を付けられることです。

1.Method();                 // Method(this int x)
"1".ToString().Method();    // Method(this string x)

static class OverloadExtensions
{
    public static void Method(this int x) => Console.WriteLine("Method(this int x)");
    public static void Method(this string x) => Console.WriteLine("Method(this string x)");
}

このコードでは、Method というメソッドが二つ定義されています。引数が異なるので、これは正しいコードです。
これらのメソッドの呼び出し元では、引数がそれぞれ、intstring なので対応する引数を持つメソッドが呼ばれます。

■ 親子関係の型でのオーバーロード

C# では (他の言語でも当たり前にできるのかもしれませんが) 継承の親子関係の型でもオーバーロードができます。使われる際には最も適切なものが使われます。
この例では、自身もしくは親の中で一番近いものが選ばれました。A2 は A3 にできないので A1 のメソッドが選ばれ、A4 も一番近い A3 のメソッドが選ばれました。

(new A1()).Method();    // Method(this A1 x)
(new A2()).Method();    // Method(this A1 x)
(new A3()).Method();    // Method(this A3 x)
(new A4()).Method();    // Method(this A3 x)

class A1{}
class A2 : A1{}
class A3 : A2{}
class A4 : A3{}

static class OverloadExtensions
{
    public static void Method(this A1 x) => Console.WriteLine("Method(this A1 x)");
    public static void Method(this A3 x) => Console.WriteLine("Method(this A3 x)");
}

この選択は、インスタンスの実際の型ではなく、変数の型で評価されます。次の例では、中身が A4 でも変数の型が A2 であれば、A2 として扱われていることがわかります。

A2 a4_1 = new A4(); a4_1.Method();    // Method(this A1 x)
A4 a4_2 = new A4(); a4_2.Method();    // Method(this A3 x)

class A1{}
class A2 : A1{}
class A3 : A2{}
class A4 : A3{}

static class OverloadExtensions
{
    public static void Method(this A1 x) => Console.WriteLine("Method(this A1 x)");
    public static void Method(this A3 x) => Console.WriteLine("Method(this A3 x)");
}

■ object 型

親子関係の型が設計できるので、object 型も設定できます。理屈は単純で簡単なのですが、なかなか刺激的なコードになりますね。
こんなコードがプロダクトコードに出てきたら怖くて泣いてしまうかもしれません......。

((object)1).Method();   // Method(this object x)
1.Method();             // Method(this int x)

static class OverloadExtensions
{
    public static void Method(this object x) => Console.WriteLine("Method(this object x)");
    public static void Method(this int x) => Console.WriteLine("Method(this int x)");
}

まとめ

今回はわかってはいても実際に書くことはそうそうない、親子関係の型の引数のオーバーロードを確認してみました。