メタプログラミング c#

Post on 01-Nov-2014

7 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

Room metro #23 大阪 & Windows Phone Arch特別編 ~めとべやスペシャルサンクスDay~http://metrostyledev.net/index.php/event/20131026/ 2014年3月1日(土)

TRANSCRIPT

メタプログラミング 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. デリゲートを生成

メタプログラミング : 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)

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!

top related