.NET Framework言語でクラスのプロパティへのアクセスやメソッドの呼び出しを動的に行う場合、そのメンバを保持するクラスの Type
オブジェクトから PropertyInfo
オブジェクトや MethodInfo
オブジェクトを取得してアクセスする…というのが.NET Framework 1.0の頃から使える方法でした。
C#言語での簡単な例を次に示します。
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
33
34
35
36
37
38
39
| - | - | | | - | ! ! | | - | - | | - ! | | - ! | | | - ! | | - ! ! ! ! |
|
この方法の欠点は、とにかく実行速度が遅いことです。
最新の.NET Frameworkではそこそこ改善されていますが、それでも静的アクセスと比べると文字通り桁違いに遅いです。
もう少しマシな速度の出る動的アクセス手法は無いものか…。
というわけで(動的アクセスのためというわけではないでしょうが) .NET Framework 3.5 から登場したのが式木(Expression Trees)です。
式木とは、簡単に言ってしまえば x + y
のようなコードをそっくりそのままデータとして保持してしまう仕組みです。
.NET Framework 3.5 では単文のラムダ式相当のコード*1のみ保持できましたが、 .NET Framework 4.0 では条件分岐やループを始めとした構文木を保持できるようになっています。
式木について詳しくは次のサイトを参照してください。
そんなわけでC#の簡単なサンプルを作ってみました。
静的アクセス、静的デリゲート呼び出し、 PropertyInfo
利用、 MethodInfo
利用、式木利用の5タイプ(式木は2通りなので全6通り)についてプロパティ値の取得&設定を100万回繰り返し、所要時間を計測しています。
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | - | - | ! | | - | | - | | | ! - | - | | | ! ! | - | | | | ! | | - | - | | | ! ! | - | | | | ! | | - | - | | | ! ! | - | | | | | ! | | | - | - | | | ! ! | - | | | | ! - | | | | | | | | ! | - | | ! - | | - ! | | ! | - ! | | | | | ! | - ! | | | | | | ! - ! - ! ! | - ! - ! | | | - ! | - ! | - ! | | | | | - ! | | | | | | | - ! | | | | | | | - ! | ! | | - | ! - ! | - ! | - ! | - | ! | | | | - ! | | | | | - ! | | | | | | | - ! | ! | ! ! ! |
|
このコードをVC#2008(.NET Framework 3.5)、VC#2010(.NET Framework 4.0)でそれぞれ実行した結果の出力は次の通りです。
数字の単位はミリ秒です。
VC#2008ではコード先頭の #define VCS2010
をコメントアウトしています。
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 8 9 10 |
|
ご覧の通り、 PropertyInfo
や MethodInfo
を用いる方法と比べて圧倒的に速いです。
特にVC#2008ではデリゲート呼び出しによる静的アクセスに肉薄する勢いです。
VC#2010だとちょっと遅くなっているのが気になりますが、それでも十分速いと言えるでしょう*2。
なお、ここまで高速になるのは式木をコンパイルしデリゲート化したものを利用した場合です。
式木のコンパイルにはそれなりの時間が掛かるため、デリゲートをキャッシュする等して同じ式木を何度もコンパイルしないようする工夫が必要です。