C# 4.0の新機能(1) dynamic

androidを触ってると無性に.NETが恋しくなるので、まだ触ってなかったC# 4.0にトライしてみることにしました。dynamicに関して参考にしたサイトはこんな感じです。これだけ読めば問題ない気がするのだが自分なりにまとめておくことにします。


MSDN dynamic 型の使用 (C# プログラミング ガイド)
MSDN dynamic (C# リファレンス)

C# 4.0 の新機能
C# 4.0 の dynamic キーワードの使用

CSharp 4.0 Specification.doc (English)


Visual C# 2010 では、dynamic という新しい型が導入されています。dynamicを使用することで動的型付け変数を定義できます。dynamic自体は静的な型ですが、型チェックが(式、変数共に)プログラムの実行時に行われます(コンパイル時ではない)。dynamicができて嬉しいことはこんな感じ。

  1. COMObjectの操作、リフレクション使用などで処理するObjectが曖昧な場合
  2. PythonRubyなど動的言語との連携時

まずは書いてみます。宣言して10で初期化してConsoleに出力すると10と表示されます。

dynamic number = 10;
Console.WriteLine(number);

          • -

10

varと使い方が同じように感じますがvarとは根本的に違います。varでは静的型指定が強化および向上します。初期化子から返される実際の型を確認しているコンパイラが、変数の型を推測できるようにすることが目的です。それに対して、dynamicは静的型指定を完全に回避します。dynamic型はコンパイラに変数の型を一切推測しないように指示します。それにより、できること、できないことに差異があります
(1) dynamicは宣言時に初期化しなくてもよい(varは初期化が必要)
(2) varはローカル変数のみだが、dynamicはクラスのプロパティ定義やメソッドに使える

//(1)の例 dynamicはコンパイルが通る
dynamic number;
number = 10;


//(1)の例 varはコンパイルエラー
var number;
number = 10;


//varだと下記のように書くことが必要
var number = 10;


//(2)の例 dynamicはコンパイルが通る
public dynamic Exam01()
{
  dynamic number = 10;
  return number;
}


//同じくコンパイルが通るクラスプロパティ
public dynamic Exam02 { get; set; }


//(2)の例 varはコンパイルが通らない
public var Exam01()
{
  var number = 10;
  return number;
}


//同じくコンパイルが通らないクラスプロパティ
public var Exam02 { get; set; }

次にObjectとの違い。コンパイラではdynamic を宣言した変数のオブジェクトはあらゆる操作をサポートしていると想定します。よって、実行時にはオブジェクトが存在すると想定してオブジェクトのメソッドを呼び出すコードを作成することができます。ですので、dynamic型を返すGetSomeReturnValueメソッドがある場合、dynamicでは存在しないメソッドを呼び出すことができます。下記の場合だと実行時にエラーになります。Objectだと当然コンパイルエラーになります。

public dynamic Exam03()
{
  dynamic p = GetSomeReturnValue();
  //↓実行時エラー
  p.DoSomething();
  return p;
}

private dynamic GetSomeReturnValue(){ return 10; }


public object Exam03()
{
  object o = GetSomeReturnObject();
  //↓コンパイルエラー
  o.DoSomething();
  return o;
}

private object GetSomeReturnObject(){ return 10; }

なるほど、なるほど。なんとなく輪郭が分かってきました。dynamicができて嬉しいことの理由が。あたしにとって一番身近なリフレクション使用を例にその嬉しさを体感してみます。まずnamespace:Calc/Assembly名:CalcでCalcSampleというクラスを作ります。中身はxとyをAddして返すAddメソッドを1つ。これをリフレクションで使用します。

Calc.dll
namespace Calc
{
  public classCalcSample
  {
    public int Add(int x, int y) { return x + y; }
  }
}

//今までの書き方
private void UseReflection()
{
  var lib = Assembly.LoadFrom(@"C:\Work\CSharp4\Calc\bin\Release\Calc.dll");
  var type = lib.GetType("Calc.CalcSample");
  var calc = Activator.CreateInstance(type);
  var add = type.GetMethod("Add");
  Console.WriteLine(add.Invoke(calc, new object[] { 1, 2 }));
}


//dynamicを使った書き方
private void UseReflection()
{
  var lib = Assembly.LoadFrom(@"C:\Work\CSharp4\Calc\bin\Release\Calc.dll");
  var type = lib.GetType("Calc.CalcSample");
  var calc = Activator.CreateInstance(type);
  Console.WriteLine(calc.Add(1, 2));
}

大分スッキリしたコード。そしてあたし自身もスッキリ。まだまだ便利に使えそうです。参考サイトでも紹介されていたこちらでは、Creating a dynamic xml reader with C# 4.0 XMLを読んだあと大変便利に値にアクセスできる仕組みをdynamicを使って実現してます。ということでざーっとdynamicを学びました。次はもう1つの目玉のオプション引数・名前付き引数について学びます。→C# 4.0の新機能(2) Named and optional parameters

補足ですが、

  • 動的な型はtypeofなどが使えません。
  • dynamicは予約語ではありません。