ECA ルール・メタプログラミング 機構を有するアクティブ …...なメタプログラミング機構を有するルール言語の導入によ り,アクティブルールの適用範囲の拡大と応用システム開発
メタプログラミング C#
-
Upload
fujio-kojima -
Category
Technology
-
view
7 -
download
1
description
Transcript of メタプログラミング C#
メタプログラミング C#
小島 富治雄ROOM METRO #23 大阪
2014-03-01
自己紹介
• 小島 富治雄• @Fujiwo• 福井コンピュータアーキテクト株式会社
• Microsoft MVP C# (2005-2014)
本日の資料
• スライドhttp://slidesha.re/1mMiXAz
• サンプル コードhttp://1drv.ms/NbF2fF• メタプログラミング入門 - 目次 - 翔ソフトウェア (Sho's)http://bit.ly/1hz6jFT
3
• 2014/03/22 全国でオフライン セッション• 北陸会場 : 石川工業高等専門学校• 申し込み : http://atnd.org/events/47189
本日のゴール
•C# でのメタプログラミングに興味を• 多くは Visual Basic でも可
メタとは
• メタ (meta) は、「高次な-」「超-」等の意味の接頭語• ギリシャ語から
• プログラミングでは• メタプログラミング• メタクラス• クラスがインスタンスとなるクラス
• メタデータ• データが持つそのデータ自身についての付加的なデータ
メタプログラミングとは
• 高次なプログラミング• プログラムを対象とするプログラムを書く
• プログラムを操作 / 出力するプログラムを書く• プログラムでプログラムを出力すると
手でプログラムを書くよりも効率的な場合が
どんな問題を解こうとしてる ?
DRY (Don't repeat yourself) の原則
• 繰り返しを避けたい• 似たようなプログラミングを繰り返し書きたくない
• オブジェクト指向プログラミングやジェネリック プログラミングだけでは解決できない繰り返しを解決• 状況に応じたパラダイムの使い分け
実行時の環境に対応
• ビルド時でなく、実行時にプログラムを書きたい• 「クラスやメソッドはビルド時までに完成してない
といけない。実行時には追加 / 変更できない」• なんで ?
メタプログラミングが有効な例
• コンパイラー / インタープリター• ホスト言語のソースコードから対象言語のプログラムを生成
• O/R マッパー• クラスやオブジェクトから SQL を生成
• モック (mock) オブジェクト• 「モック ( ユニットテストで用いられる代用のオブジェ
クト ) を生成」するプログラムを生成
メタプログラミングが有効な例
• XML や JSON の入出力• 「クラスやオブジェクトから XML や JSON を生成 /
XML や JSON からクラスやオブジェクトを生成」するプログラムを生成
• Web アプリケーション• クライアント側で動作するプログラム
(JavaScript 等 ) をサーバー側で動的に生成
メタプログラミングの例
メタプログラミング C// C のマクロ (危険 )
#define SWAP(x, y, type) { type temporary__; temporary__ = x; x = y; y = temporary__; }
int main(void){ int a = 1; int b = 2;
SWAP(a, b, int);
return 0;}
int main(void)
{
int a = 1;
int b = 2;
{
int temporary__;
temporary__ = a;
a = b;
b = temporary__;
}
return 0;
}
プリコンパイラー
メタプログラミング C++
template <int N>
struct Factorial
{
enum { value = N *
Factorial<N - 1>::value };
};
template <>
struct Factorial<0>
{
enum { value = 1 };
};
int main()
{
int x = Factorial<3>::value;
return 0;
}
struct Factorial0 { enum { value = 1 }; };
struct Factorial1 { enum { value = 1 * Factorial0::value }; };
struct Factorial2 { enum { value = 2 * Factorial1::value }; };
struct Factorial3 { enum { value = 3 * Factorial2::value }; };
int main()
{
int x = Factorial3::value;
return 0;
}
コンパイラー
C#/.NET におけるメタプログラミングの手段
• T4 (Text Template Transformation Toolkit) Template
• CodeDOM (Code Document Object Model)
•リフレクション (Emit)
•式木• Roslyn
T4 (Text Template Transformation Toolkit) Template
• Visual Studio でコード生成• T4
テキスト テンプレートを使用したデザイン時コード生成 - MSDN
CodeDOM (Code Document Object Model)
• System.CodeDom 名前空間や System.CodeDom.Compiler 名前空間• C# や Visual Basic 等のコードを生成• コンパイルしてアセンブリを生成
CodeDOM CodeDOMProvider
ソース コード(C# 、 VB 、 JScript
)
アセンブリ
GenerateCodeFromNamespace
CompileAssemblyFromDom
CodeDOM: Demo
• Hello world! の動的生成namespace CodeDomHelloWorldDemo{ using System;
class Program { static void Main() { Console.WriteLine("Hello world!"); Console.ReadKey(); } }}
リフレクション
• System.Reflection 名前空間• クラスやインスタンスに関する情報 ( メタデータ ) を取
得し、メンバーを呼び出したりできる
• System.Reflection.Emit 名前空間• CIL (Common Intermediate Language) からクラス等
を動的生成
式木
• System.Linq.Expressions 名前空間• 式木を生成し、動的にプログラムを生成
式木 Expression<Func<Employee, bool>> expression = employee => employee.Name.Contains(" 山 ");
Parameters
Body Object
Method
Arguments
Expression
Member
employee => employee.Name.Contains(" 山 ")
employee.Name
Contains
employee
Name
“ 山”
employee
employee.Name.Contains(" 山 ")
Roslyn
• C# や Visual Basic のコンパイラーの内部の API 等を公開• "Compiler as a Service“
• C# や Visual Basic のソースコード解析機能• C# のソースコードから、プログラムを生成
リフレクション : Demo
• 動的プログラム生成の前に「普通の」リフレクション• リフレクションによるデータバインド• 実行時に型のメタデータを取得
Assembly
Module
Type・ Class・ Interface・ Value Type
FieldInfo
PropertyInfo
EventInfo
MethodInfoConstructorInfo
ParameterInfo
リフレクションの欠点
遅い
メタプログラミング : Demo
• 簡単なメソッド (Add) の生成
static int Add(int x, int y){ return x + y;}
メタプログラミング : DemoReflection.Emit による Add メソッドの動的生成
• 簡単なメソッド (Add) の生成• DynamicMethod
1. CIL (共通中間言語 ) を組み立てる
2. デリゲートを生成
ILSpy
• CIL (共通中間言語 ) を調べられる• ILSpy - SharpDevelop - SourceForge.net
メタプログラミング : DemoReflection.Emit による Add メソッドの動的生成
var method = new DynamicMethod(“add”, …);
method.DefineParameter(1, ParameterAttributes.In, "x");
method.DefineParameter(2, ParameterAttributes.In, “y");
var generator = method.GetILGenerator();
generator.Emit(opcode: OpCodes.Ldarg_0);
generator.Emit(opcode: OpCodes.Ldarg_1);
generator.Emit(opcode: OpCodes.Add );
generator.Emit(opcode: OpCodes.Ret );
Func<int, int, int> newDelegate = method.CreateDelegate(…);
メタプログラミング : Demo式木による Add メソッドの動的生成
• 簡単なメソッド (Add) の生成1. 式木を組み立てる
2. コンパイル +
x y
=>
(x, y)
式の種類• Expression の派生クラス一覧 - 継承階層 - Expression クラス - MSDN ライブラリ
Visual Studio のデバッガーで add 式の構造を見る
(x, y) => x + y の式木
メタプログラミング : Demo式木による Add メソッドの動的生成
var x = Expression.Parameter(type: typeof(int));
var y = Expression.Parameter(type: typeof(int));
var add = Expression.Add (left: x, right: y);
var lambda = Expression.Lambda (add, x, y );
Func<int, int, int> newDelegate =(Func<int, int,
int>)lambda.Compile();
メタプログラミング : DemoRoslyn による Add メソッドの動的生成
• 簡単なメソッド (Add) の生成1. スクリプトエンジンの作成
2. 名前空間のインポート
3. ソースコード ( 文字列 ) の実行
Roslyn の入手先• Microsoft “Roslyn” CTP
• Visual Studio- NuGet
メタプログラミング : DemoRoslyn による Add メソッドの動的生成
var engine = new ScriptEngine();
var session = engine.CreateSession();
session.ImportNamespace(…);
Func<int, int, int> newDelegate =session.Execute ("(Func<int, int, int>)((x, y) => x + y)");
メタプログラミングによるプログラム生成の欠点
• ( リフレクションほどではないが)遅い• エラーが分かりにくい
メタプログラミングの実行速度 : Demo
• 生成速度の比較1. Reflection.Emit による Add
2. 式木による Add
3. Roslyn による Add
• 実行速度の比較1. 静的な Add
2. Reflection.Emit による Add
3. 式木による Add
4. Roslyn による Add
メタプログラミングの実行速度 : 結果
• 生成速度の比較
メタプログラミングの実行速度 : 結果
• 実行速度の比較
メタプログラミングの実行速度の改善
• 生成が遅い• 呼び出しの度に生成すると遅い
→ キャッシュで改善
生成したデリゲートのキャッシュ
• デリゲートのキャッシュを用意Dictionary<string, Delegate> methods = new Dictionary<string, Delegate>();
1. キャッシュにない場合は、デリゲートを生成してキャッシュに入れる
2. キャッシュ内のデリゲートを呼ぶ
メタプログラミングの実行速度の改善 : Demo• メソッド呼び出しの速度の比較
1. 静的なメソッド呼び出し
2. 動的なメソッド呼び出し1. リフレクション
2. dynamic
3. 動的にメソッドを生成して呼び出し - キャッシュ無し1. Reflection.Emit
2. 式木
3. Roslyn
4. 動的メソッドを生成して呼び出し - キャッシュ有り1. Reflection.Emit
2. 式木
3. Roslyn
メタプログラミングの実行速度 : 結果
• 生成速度の比較
メタプログラミングの実行速度 : 結果
• 実行速度の比較
メタプログラミングの実行速度の改善 : 結果
メタプログラミング応用例 : Demo
• デバッグ情報の出力• クラスやオブジェクト等を、型情報を使って文字列に変換
し、テストやデバッグで用いる。
• ASP.NET (Web アプリケーション /Web サービス ) のサーバー側の処理• クラスやオブジェクト等を、型情報を使って HTML に変
換
• XML シリアライザー• クラスやオブジェクト等を、型情報を使って XML に変換
メタプログラミング - 応用編 : 続き
• オブジェクトの文字列変換を静的/動的に行う
• オブジェクトの文字列変換のメタプログラミング
• オブジェクトの文字列変換のメタプログラミング (Reflection.Emit 編)
• オブジェクトの文字列変換のメタプログラミング (式木編)
• オブジェクトの文字列変換のメタプログラミング (Roslyn 編)
• オブジェクトの文字列変換のメタプログラミング (パフォーマンスのテスト)
まとめ
• C# ( や VB) でもメタプログラミングはできる• CodeDOM 、 Reflection.Emit 、式木、 Roslyn
•今後は Roslyn に期待
•Let’s enjoy metaprogramming!