Frienldyはdynamicを使うライブラリです。
で、dynamicって書いててちょっと直感的でない時があるんです。
よく考えると、「そうだよね。」ってなるんですけど、僕もハマったので書いておきます。
引数に渡すと、対象の関数まで動的になる
例えば、こんなメソッドがあったとします。
IEnumerable<int> Func(paramsint[] val) { return val; }
まずは、普通に使ってみましょう。もちろんコンパイル通ります。
Func(3, 2, 1).Where(e => e == 2);
で、引数にdynamicを混ぜてみます。で、ビルドすると・・・
dynamic val = 0; Func(3, 2, 1, val).Where(e => e == 2);
No...コンパイルエラーです。
しかも、意味わからん感じです。
ちょっとWhereの前の.でインテリセンスを見てみましょう。
メソッドが動的になっていますね。
最初は、「なんでやねん!」って思いました。
でもこうならざるを得ないんですよね。
オーバーロードの解決が出来ないから
言われてみると、「確かにね」なんですね。
例えば、以下の二つの関数があるとき・・・
int Func(int val) { return val; } string Func(string val) { return val; }
これは実行時まで戻り値の型が分からないんですね。
だから var って書いてますけど ret は dynamic型 なのです。
void Call(dynamic val) { //実行するまで戻り値わからんやん・・・ val ret = Func(val); }
型変換
もう一つハマったのが型変換です。
DynamicObjectと言うのがあって、これを継承したクラスをdynamicに入れると、動的な挙動をコントロールできるというものです。
で、TryConvertをoverrideすれば型変換に関する処理をカスタマイズできます。
例えば、シンプルな例で、intにキャストすると10になるというクラスを書いてみます。
publicclass MyDynamic : DynamicObject { publicoverridebool TryConvert(ConvertBinder binder, outobject result) { result = (int)10; returntrue; } }
これは、もちろん変換できます。
dynamic d = new MyDynamic(); int i = (int)d; int ii = d;
なのに、関数の引数に渡す時はダメなんですよね。なんでー?
int Func(int val) { return val; } void Call() { dynamic d = new MyDynamic(); //例外が発生する・・・//型 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException'の例外が System.Core.dll で発生しましたが、ユーザー コード内ではハンドルされませんでした Func(d); }
まあ、多分これもオーバーロードと絡んでて、複数の変換の可能性を解決できないからでしょうね。残念・・・
追記
オーバーロードとオーバーライドって、いつもどっちがどっちか分からなくなりますよね・・・