こんな Tuple が欲しかった的な(即興の落書き)
dynamic は便利な機能だけど、言語仕様に dynamic キーワードを持ち込まざるを得なかったのはちょっと残念だなと思う。むしろ、演算子でいいんじゃない?とか思わなくもない。
dynamic dx = any; dx.Foo(); dx.Bar(); // 実際の DynamicObject には、public なコンストラクタはない // 明示的変換やファクトリメソッドがあってもいいんじゃね? var dx = new DynamicObject(any); dx->Foo(); dx->Bar(); // パフォーマンスに影響があると思われるが、非 DynamicObject に対して呼びだしたら // その場で暗黙的に DynamicObject に変換されてもいいんじゃない?と any->Foo();
みたいにね...どうかな?インデクサあたりで問題になりそうだけどね...話題がそれているようで、一応前置きだったりします。
.NET4 の Tuple は dynamic と比べると「誰もが .NET 2.0/3.5 で作成していたであろうクラス」なレベルで収まっており、かなり残念な印象があった。*1 それなりの人が、anonymous type のような「動的な型」としての何かを望んでいたのではないだろうか?と思ったりする。ざっくり言うと、
- Tuple 型は型パラメータの型情報だけでしか区別できないので new { Key="", Value="" } と new { Name="", Value="" } が、どちらも Tuple
になってしまって区別できない。 - Tuple 型が静的な型なので string Item1 が Key なのか Name なのか、それとも別の何かなのかをコードに表現しにくい。*2
のがダメだと思うんですよね。
// たとえば、こんな。 public tuple F(int n) { return new { Number = n }; } // 使うときは var で受ける(dynamic や object でもいいけどさ) var x = F(1); Console.WriteLine(x.Number); // コンパイル後のイメージは、dynamic と同じく属性 [return: Tuple(Tuple.Create("Number"), typeof(int))] public object F(int n) { // 現実的には、コンパイラが生成する TupleAttribute には、 // この返される匿名"型"を引数すれば十分 return new { Number = n }; } // もしくは Tuple<> を用いてメンバー名だけを属性に保持 [return: Tuple("Number")] public Tuple<int> F(int n) { ... }
- anonymous type は今まで通り作成する
- その anonymous type が tuple として公開された場合、anonymous type の可視性をそれにあわせて protected/internal/public へと変更する
- アセンブリ境界をまたぐ場合、公開された匿名型をそのまま使用しないで、使用する側のアセンブリに改めて匿名型として作成する。(それが再公開されない限りは private である)
- 上記のアセンブリ境界をまたいだ受け渡しのため、匿名型同士の代入互換性を確保(匿名型のプロパティは読み取り専用なので、問題にはなりにくいだろう)
ぐらいの、dynamic の導入よりも少ない変更で実現しそうなのですけどねえ。
Tuple.Create(...) の挙動も現在の Tuple 型の仕様のままで一般形として使えると思うんですね。入力系は一般系に限定しちゃうことにして、
public IEnumerable<tuple> ToNameValue<T>(params Tuple<string, T>[] items) { foreach (var item in items) yield return new { Name = item.Item1, Value = item.Item2 }; }
うーん、入力考えるといまいちイケてないな。