<目次>
(1) C#のdynamic型とは?使いどころやvarとの違いもご紹介
(1-1) dynamic型とは?
(1-2) dynamic型の使いどころ
(1-3) 動作確認サンプル①:動的に型を変更
(1-4) 動作確認サンプル②:クラスのオブジェクトを割り当て
(1-5) varとの違いは?
(1) C#のdynamic型とは?使いどころやvarとの違いもご紹介
(1-1) dynamic型とは?
dynamic型で定義された変数はコンパイル時(compile time)の型のチェックを回避し、実行時(runtime)する事が出来ます。内部的には、コンパイラがdynamic型をobject型に変換し、実際の型は実行時に決定される、という流れです。
(1-2) dynamic型の使いどころ
dynamic型は変数のデータ型が1つに確定しない場合に役に立ちます。具体的な用途の例は以下のようなシーンが想定されます。
Document Object Modelの略で、HTMLやXMLを「オブジェクト」として捉えてJavaScript等からアクセスするためのインターフェイス(API)です。具体的には画面をwindowやdocumentといった単位に見立て、各要素(テキストボックス、プルダウン、ラジオボタンなど)にアクセスしていきます。
ソフトウェア部品(例:コンパイルされたバイナリのライブラリ)の「再利用」を可能にした技術です。COMの登場以前はクライアント側のコンポーネントがあるライブラリ(例:C++のライブラリ)を使用しようと思った場合に、そのライブラリをセットでのコンパイルが必要でした(これをしないとバイナリ内のメソッドやファンクションを特定できず、呼び出しができない)。
(1-3) 動作確認サンプル①:動的に型を変更
dynamic型の変数に様々な型の値を代入していき、代入する度に変化していく様子が確認しています。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestProject
{
class DynamicTypeTest1
{
public void Test()
{
Console.WriteLine("##### DYNAMIC TYPE TEST#1 START #####");
//# int型で設定
dynamic testvalue = 10;
Console.WriteLine("値: {0}, 型: {1}", testvalue, testvalue.GetType());
//# string型に変更
testvalue = "This is an Apple";
Console.WriteLine("値: {0}, 型: {1}", testvalue, testvalue.GetType());
//# bool型に変更
testvalue = false;
Console.WriteLine("値: {0}, 型: {1}", testvalue, testvalue.GetType());
//# long型に変更
testvalue = 1L;
Console.WriteLine("値: {0}, 型: {1}", testvalue, testvalue.GetType());
//# double型に変更
testvalue = 0.005;
Console.WriteLine("値: {0}, 型: {1}", testvalue, testvalue.GetType());
Console.WriteLine("##### DYNAMIC TYPE TEST#1 END #####");
}
}
}


##### DYNAMIC TYPE TEST#1 START ##### 値: 10, 型: System.Int32 値: This is an Apple, 型: System.String 値: False, 型: System.Boolean 値: 1, 型: System.Int64 値: 0.005, 型: System.Double ##### DYNAMIC TYPE TEST#1 END #####

(1-4) 動作確認サンプル②:クラスのオブジェクトを割り当て
次にdynamic型の変数に、カスタムクラス(例:Fruit)のオブジェクトを割り当てる例をご紹介します。
前半の(パート#1)ではdynamicを使わずに通常の書き方(Fruit型の変数にFruit型オブジェクトを割り当てる)をしており、メソッドに不正な引数を与えると、当然ながらコンパイルエラーになっています。
後半の(パート#2)ではdynamic型にFruit型のオブジェクトを割り当てており、同様にメソッドに不正な引数を与えていますが、コンパイル時点ではエラーになっていません。
(図141)

コンパイルエラーの部分(24行目)をコメントアウトして実行すると、dynamicの特性として実行時(ランタイム)にエラーを検知するので、実行時に不正な引数のためエラーになります。
(図142)

(サンプル)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TestProject.Models;
namespace TestProject
{
class DynamicTypeTest2
{
public void Test()
{
Console.WriteLine("##### DYNAMIC TYPE TEST#2 START #####");
//# (パート#1)通常の書き方
//# Fruit型にFruitクラスのオブジェクトを割り当て
Fruit fr1 = new Fruit();
fr1.Id = "A001";
fr1.Name = "Apple";
fr1.Price = 200;
fr1.Origin = "青森";
//fr1.AddPrice("Dummy1", "Dummy2");
////# (パート#2)dynamic型を使った書き方
//# dynamic型にFruitクラスのオブジェクトを割り当て
dynamic fr2 = new Fruit();
fr2.Id = "A002";
fr2.Name = "Banana";
fr2.Price = 90;
fr2.Origin = "インド";
fr2.AddPrice("Dummy1", "Dummy2");
Console.WriteLine("##### DYNAMIC TYPE TEST#2 END #####");
}
}
}

(サンプル)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestProject
{
class Home
{
static void Main(string[] args)
{
DynamicTypeTest2 dt2 = new DynamicTypeTest2();
dt2.Test();
}
}
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TestProject.Models
{
public class Fruit
{
public string Id { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public string Origin { get; set; }
public DateTime HarvestDate { get; set; }
public double AddPrice(int Price)
{
double prc = Price;
prc = prc * 1.1;
return prc;
}
}
}
プログラム全体の構造は次のようになっています。

(1-5) varとの違いは?
(表)
| ■項目 | ■var | ■dynamic |
| 導入時期 | C#3.0 | C#4.0 |
| 定義 | varキーワードを使用 | dynamicキーワードを使用 |
| 特性 (dynamic/static) |
staticに型を決定 (コンパイル時に判定) |
dynamicに型を決定 (実行時に判定) |
| 初期化のタイミング | 定義時の初期化は「必須」 (コンパイラが判断できるよう) |
定義時の初期化は「任意」 (コンパイル時に型が確定しない為) |
| 戻り値での使用可否 | NG (function内のローカル変数としてのみ使用可能) |
OK |