だらだらやるよ。

こげつのIT技術メモ

C#3.0機能紹介その5。匿名型

匿名型
匿名型のオブジェクトを生成することができます。
例はこんな感じ。
即興のクラスインスタンスが生成できる感じですね。

var a = new { Test = "",Test2 = "a" };
var b = new { Test = "a",Test2 = "b" };
var c = new { Test = "abc" };

プロパティの型は暗黙的に判断されます。なのでnullを指定することは無理そう。
プロパティの指定がまったく同じならば、同一型とみなされます。
上の例だとaとbが同じですね、順番も同じ必要があるので注意!

foreach(var ab in new[] { a,b }) {
    Console.WriteLine(ab.Test);
}

実行時に動的に型を判別しているわけではないので、ダックタイピングはできないんです。

//当然ながらダックタイピングはできない。
//foreach(var abc in new[] { a,b,c }) {
//    Console.WriteLine(ab.Test);    
//}

本来なら匿名型にメソッドを持たせることはできないのですが
デリゲートやラムダ式を使うことにより、設定することができます。
個人的にここまでやるならちゃんとクラス定義したほうがいいと思うのですが、一応。
まず、デリゲートを定義しておきます。

private delegate void MyDelegate(string s);
private static void DelegateMethod(string s) {
	Console.WriteLine(s);
}

使うときはこんな感じで。

var d1 = new { Method = new MyDelegate(Write) };
var d2 = new { Method = new MyDelegate(s => { Console.WriteLine(s); }) };
var d3 = new { Method = new MyDelegate(delegate(String s) { Console.WriteLine(s); }) };

d2とd3はそれぞれラムダ式とデリゲートで動的にメソッドを定義しています。

わざわざMyDelegateなんて作るのが面倒だなぁ、て場合はこんな感じ
あらかじめ用意されているActionやFuncを使用します。

var e1 = new { Method = (Action<String>)(s => { Console.WriteLine(s); }) };
var e2 = new { Method = (Action<String>)delegate(String s) { Console.WriteLine(s); } };
var e3 = new {Method = (Func<String,String>)(s=>s.ToUpper())};

ちなみにキャストせずに使用しようとすると、エラーがでます。
varの型推論とぶつかって正常に型が判断できないためかな。

//var e4 = new { Method = s => { Console.WriteLine(s); } };
//var e5 = new { Method = delegate(String s) { Console.WriteLine(s); } };


値の変更はできない模様。

//a.Test = "test";

こんな感じでインスタンスを作り直すのならOK

a = new { Test = "abc",Test2 = a.Test2 };

プロパティはC#の場合リードオンリーなんですね*1、参照型のオブジェクトのメソッドを実行して変更することはできます。

var f = new { Test = new List<String> { "a","b" } };
f.Test.Add("c");
f.Test.ForEach(s=>{Console.WriteLine(s);});

*1:VB.NETの場合変更可能らしいです