|
|
連載:C# 4入門
第1回 dynamic型
株式会社ピーデー 川俣 晶
2010/07/16 |
|
|
dynamic型
C#は従来より、コンパイル時に定義を知らないオブジェクトが持つ情報にアクセスすることができる。リフレクションという機能を使うだけでよい。しかし、これはいうほど容易ではなかった。
using System;
using System.Reflection;
class A
{
public readonly string MyName = "山田太郎";
public static object GetObjectA() { return new A(); }
}
class Program
{
static void Main(string[] args)
{
object a = A.GetObjectA();
var name = a.GetType().GetField("MyName").GetValue(a);
Console.WriteLine(name);
}
}
|
|
リスト3 リフレクションを使ったメンバのアクセス |
見てのとおり、メソッドMainはどのような型のオブジェクトが返ってきたのか何も知らないが、リフレクションの機能で、それに属するフィールドの値を得ることができている。つまり、これはいわゆる「動的」な処理である。
C# 4で導入されたdynamic型は、これを大幅に簡素化してくれる。
using System;
class A
{
public readonly string MyName = "山田太郎";
public static dynamic GetObjectA() { return new A(); }
}
class Program
{
static void Main(string[] args)
{
dynamic a = A.GetObjectA();
Console.WriteLine(a.MyName);
}
}
|
|
リスト4 dynamic型を使ったメンバのアクセス |
もちろん、MainメソッドはGetObjectAメソッドから返ってきたオブジェクトがA型であるとはまったく知らないが、MyNameという名前のフィールドの値を参照することができている。これは、単に名前が一致しているという理由でアクセス可能になっているだけであり、リフレクションを使った例(リスト3)と機能的には同じである。
ちなみに、名前の一致はコンパイル時ではなく実行時にチェックされるため、つづりを間違えてもコンパイル・エラーではなく、実行時に例外を出すことになる。また、実行時に目的の名前を持つメンバを探す関係上、実行速度も遅くなりがちである。
ダック・タイピング
dynamic型の特徴の1つは、定義がなくてもアクセスできることだが、ある状況では定義があってもdynamic型を経由しないとアクセスできないことがある。
以下は2つの「鳥」をクラスとして定義しているが、特に継承関係はない。まったく独立した存在である。このような場合、普通の方法では「鳴け」メソッドは記述できない。別の実装にアクセスできるとしても、あくまで特定の宣言に対する呼び出しを行うからである。このように継承関係がない場合は、共通の定義もなく、呼び出すことはできない。しかし、dynamic型を経由してしまうと、名前や引数や型さえ一致していれば呼び出せてしまう。
using System;
class 醜いアヒルの子
{
public void 鳴く()
{
Console.WriteLine("くわっ! by 醜いアヒルの子");
}
}
class 白鳥
{
public void 鳴く()
{
Console.WriteLine("くわっ! by 白鳥");
}
}
class Program
{
private static void 鳴け(dynamic 鳥)
{
鳥.鳴く();
}
static void Main(string[] args)
{
鳴け((dynamic)new 醜いアヒルの子());
鳴け((dynamic)new 白鳥());
}
}
|
|
リスト5 dynamic型経由のアクセス |
くわっ! by 醜いアヒルの子
くわっ! by 白鳥
|
|
リスト5の実行結果 |
このような「名前が同じで、同じように振る舞うなら、同じものである」というやり方を「ダック・タイピング」などの用語で呼ぶこともある。dynamic型は、それをC#で行うハードルを一気に下げてくれたといえる。
Insider.NET 記事ランキング
本日
月間