.NET Framework 4.0より、動的オブジェクトに対してのサポートが追加されています。
動的オブジェクトに関するクラスは、System.Dynamic名前空間に配置されています。
System.Dynamic名前空間は、「System.Core.dll」に存在します。
今回対象となるSystem.Dynamic.ExpandoObjectクラスも動的オブジェクトを扱う為に
追加されたクラスです。Expandoという名前が示す通り、javascriptのようにクラス定義が
行えます。
C#からこのクラスを扱う場合は、dynamicが必須となります。
どのように扱うのかは、実際にコードを見た方がイメージできると思います。
以下、サンプルです。
public class ExpandoObjectSamples01 : IExecutable { public void Execute() { ////////////////////////////////////////////////////////////////////// // // 動的オブジェクトを作成. // // System.Dynamic名前空間は、「System.Core.dll」内に存在する。 // 動的オブジェクトを利用するには、上記のDLLの他に以下のDLLも参照設定 // する必要がある。 // // ・Microsoft.CSharp.dll // dynamic obj = new System.Dynamic.ExpandoObject(); // // メンバーを定義. // // プロパティ. obj.Value = 10; // メソッド. var action = new Action<string>((line) => { Console.WriteLine(line); }); obj.WriteLine = action; // // 呼び出してみる. // obj.WriteLine(obj.Value.ToString()); obj.Value = 100; obj.WriteLine(obj.Value.ToString()); obj.Value = "hoge"; obj.WriteLine(obj.Value.ToString()); } }
上記サンプルを実行すると、
10 100 hoge
と表示されます。
今までだと、まず最初にクラスなり構造体なりを定義し、その後
インスタンス化し、値を適切に設定していました。
Python,Javascriptなどの動的言語の場合、実行時に必要となるクラス定義をその場で作成することは
珍しくありません。ExpandoObjectを利用することで、C#側でもそれが行えるようになります。
(当然VisualBasicでもC#と同じ事が行えます。)
上記のサンプルでは、WriteLineというメンバーに対して、Actionデリゲートを設定しています。
なので、当然イベントも設定することもできます。
public class ExpandoObjectSamples02 : IExecutable { public void Execute() { /////////////////////////////////////////////// // // ExpandoObjectにイベントを追加. // dynamic obj = new System.Dynamic.ExpandoObject(); // // イベント定義 // ExpandoObjectに対してイベントを定義するには // まず、イベントフィールドを定義して、それをnullで初期化 // する必要がある。 // obj.MyEvent = null; // // イベントハンドラを設定. // obj.MyEvent += new EventHandler((sender, e) => { Console.WriteLine("sender={0}", sender); }); // イベント着火. obj.MyEvent(obj, EventArgs.Empty); } }
動的言語では、クラスのメンバーの追加・削除を実行時に行う事がよくあります。
ExpandoObjectは、IDictionary
動的にメンバーの追加・削除が行えます。
public class ExpandoObjectSamples03 : IExecutable { public void Execute() { /////////////////////////////////////////////////////////////////////// // // ExpandoObjectをDictionaryとして扱う. (メンバーの追加/削除) // ExpandoObjectはIDictionary<string, object>を実装しているので // Dictionaryとしても利用出来る. // dynamic obj = new System.Dynamic.ExpandoObject(); obj.Name = "gsf_zero1"; obj.Age = 30; // // 定義されているメンバーを列挙. // IDictionary<string, object> map = obj as IDictionary<string, object>; foreach (var pair in map) { Console.WriteLine("{0}={1}", pair.Key, pair.Value); } // // Ageメンバーを削除. // map.Remove("Age"); // // 確認. // foreach (var pair in map) { Console.WriteLine("{0}={1}", pair.Key, pair.Value); } // エラーとなる. //Console.WriteLine(obj.Age); } }
また、ExpandoObjectはINotifyPropertyChangedインターフェースも実装しているので
これを利用することで、プロパティの変更タイミングを捉える事ができます。
public class ExpandoObjectSamples04 : IExecutable { public void Execute() { /////////////////////////////////////////////////////////////////////// // // ExpandoObjectをINotifyPropertyChangedとして扱う. (プロパティの変更をハンドル) // dynamic obj = new System.Dynamic.ExpandoObject(); // // イベントハンドラ設定. // (obj as INotifyPropertyChanged).PropertyChanged += (sender, e) => { Console.WriteLine("Property Changed:{0}", e.PropertyName); }; // // メンバー定義. // obj.Name = "gsf_zero1"; obj.Age = 30; // // メンバー削除. // (obj as IDictionary<string, object>).Remove("Age"); // // 値変更. // obj.Name = "gsf_zero2"; // // 実行結果: // Property Changed:Name // Property Changed:Age // Property Changed:Age // Property Changed:Name // } }
参考にしたリソースは以下の通りです。
てか、ほとんどMSDNのままですが・・・w
- ExpandoObjectクラス
- Adventures with C# 4.0 dynamic - ExpandoObject, ElasticObject, and a Twitter client in 10 minutes
- A multi-level C# 4.0 dynamic object
今回の記事では、全然記述してませんが、DynamicObjectというのもあります。
DynamicObjectについては、別の記事で書こうと思います。
2番目のリソースにて、紹介されているElasticObjectは、目から鱗でした。
================================
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場