今更 C# 4.0 のお話です。
C#で、 Execute
というメソッドにある型の引数を渡した時、次のように動作して欲しいものとします。
string
であれば string
版のオーバロードを呼ぶ。IEnumerable<T>
(T
はジェネリック型)であれば IEnumerable<T>
版のオーバロードを呼ぶ。object
版のオーバロードを呼ぶ。直接 Execute
メソッドを呼び出すのであれば特に難しいことはありません。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| - | - | - | ! | | - | ! | | - | ! | | - | | | | | ! ! ! |
|
object : Int32 object : Exception string IEnumerable<T> : T is Int32 IEnumerable<T> : T is Char
しかし、引数に渡す型がジェネリック型である場合は話が違ってきます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| - | - - ! | | | | - - ! ! | | - | | | | | ! ! ! |
|
object : Int32 object : Exception object : String object : List`1 object : Char[]
先述のコードと同じ結果を期待したのですが、引数の型に関わらず object
版のオーバロードが呼び出されてしまっています。
ジェネリック型 T
に対するオーバロード解決はコンパイル時に行われ、型制約が指定されていない以上 object
版のオーバロードにしかマッチしないためです。
そこで、 Execute
メソッドの引数を dynamic
型にキャストすることで、オーバロード解決を実行時に行うようにしてみます。
object : Int32 object : Exception string IEnumerable<T> : T is Int32 IEnumerable<T> : T is Char
見事に期待通りの動作をしてくれました。
このように、 dynamic
型を使うことで、ジェネリック型の引数に対して動的なオーバロード解決を行うことが出来ます。
もちろん実行時に解決するためのオーバヘッドはゼロではありませんが、 is
演算子で型を調べて if
文で分岐させたりリフレクションを利用したりするしかなかった C# 3.0 以前と比べれば相当マシになっていると言えるでしょう。
今回の内容は、C++のテンプレート型であればコンパイル時に行えることではありますが、そこは仕組みの違い上仕方ありません。