30
Exploring DLR 江嘉诚 2011.8.28

Dlr

Embed Size (px)

Citation preview

Page 1: Dlr

Exploring DLR

江嘉诚

2011.8.28

Page 2: Dlr

关于我

• 江嘉诚 (无厚之刃)

• 华南理工大学

• 微博:@以无厚入有间 ( 典故参见《庄子》)

• 博客:http://sharp-blade.tuita.com/

Page 3: Dlr

DLR是

• Dynamic Language Runtime

• 由 IronPython 发起人Jim Hugunin开发

• 一个构建在CLR之上的运行时

• 在.Net上构建动态语言的标准体系

The DLR's mission is to enable an ecosystem of dynamic languages on .NET.

Page 4: Dlr

动态语言需要什么

• Lexer & Parser

• 交互式脚本引擎(REPL)

• 动态加载代码的能力

• 动态类型

• 元编程(自省/魔术方法/动态修改类型)

• 其它:Stackless/Actor/Continuation

Page 5: Dlr

DLR提供了什么

• 脚本语言引擎

• 可以在运行时编译的表达式树

• 延迟绑定

• 动态语言的互操作性

Page 6: Dlr

ExpressionTree

Page 7: Dlr

ExpressionTree : Hello World

using System.Linq.Expressions;

MethodInfo method = typeof (Console)

.GetMethod( "WriteLine", new Type[] { typeof(string) } );

Expression call = Expression.Call(null, method, Expression.Constant("Hello World")) ;

Action callDelegate = Expression.Lambda<Action>(call).Compile();

callDelegate();

Console.WriteLine(“Hello World”);

Page 8: Dlr

ExpressionTree : Binary Expression

BinaryExpression add = Expression.Add(Expression.Constant(3),

Expression.Constant(5));

Func<int> addDelegate = Expression.Lambda<Func<int>>(add).Compile();

Console.WriteLine("{0}", addDelegate());

3 + 5

Page 9: Dlr

ExpressionTree : Index Expression

int[] list = { 1, 2, 3 };

IndexExpression index = Expression.ArrayAccess(

Expression.Constant(list),

Expression.Constant(1));

Expression indexAccess = Expression.Assign(index,

Expression.Constant(4));

Action indexAccessDelegate = Expression.Lambda<Action>(indexAccess).Compile();

indexAccessDelegate();

int[] list = { 1, 2, 3 }; list [1] = 4;

Page 10: Dlr

ExpressionTree : IfThenElse Expression

Expression ifExpression = Expression.IfThenElse(

Expression.Constant(true),

Expression.Call(null,

typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),

Expression.Constant("true")),

Expression.Call(null,

typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),

Expression.Constant("false"))

);

Action ifDelegate = Expression.Lambda<Action>(ifExpression).Compile();

ifDelegate();

if (true) Console.WriteLine("true"); else Console.WriteLine("false");

Page 11: Dlr

ExpressionTree : LambdaExpression

ParameterExpression x = Expression.Parameter(typeof(int), "x");

ParameterExpression y = Expression.Parameter(typeof(int), "y");

Expression<Func<int, int, int>> add = Expression

.Lambda<Func<int, int, int>>(Expression.Add(x, y), x, y);

int result = add.Compile()(3, 5);

Console.WriteLine("result is {0}", result);

Func<int, int, int> add = (x, y) => { return x + y; }; int result = add(3, 5); Console.WriteLine("result is {0}", result);

Page 12: Dlr

代码即数据

数据即代码

Page 13: Dlr

Dynamic & Late Binding

Foo foo = new Foo(); foo.act();

dynamic foo = …… // new Foo() foo.act();

Page 14: Dlr

Dynamic语法的绑定过程 dynamic num = 5; int result = num + 2; CallSite<Func<CallSite, object, int>> Site1; CallSite<Func<CallSite, object, int, object>> Site2; object num = 5; if (Site1 == null) { Site1 = CallSite<Func<CallSite, object, int>> .Create( Binder.Convert( CSharpBinderFlags.None, typeof(int), typeof(Program))); }

Page 15: Dlr

Dynamic & Late Binding

Func<CallSite, object, int> convert = Site1.Target; CallSite add = Site1; if (Site2 == null) { Site2 = CallSite<Func<CallSite, object, int, object>> .Create( Microsoft.CSharp.RuntimeBinder.Binder.BinaryOperation( CSharpBinderFlags.None, ExpressionType.Add, typeof(Program), ...)); } int result = convert(add, Site2.Target(Site2, num, 2));

Page 16: Dlr

Dynamic语法的绑定过程 dynamic num = 5; int result = num + 2;

CallSite<Func<CallSite, object, int>> Site1; CallSite<Func<CallSite, object, int, object>> Site2; object num = 5; if (Site1 == null) { Site1 = CallSite<Func<CallSite, object, int>> .Create( Binder.Convert( CSharpBinderFlags.None, typeof(int), typeof(Program))); }

Page 17: Dlr

Dynamic & Late Binding

Func<CallSite, object, int> convert = Site1.Target; if (Site2 == null) { Site2 = CallSite<Func<CallSite, object, int, object>> .Create( Binder.BinaryOperation( CSharpBinderFlags.None, ExpressionType.Add, typeof(Program), ...)); } int result = convert(Site1, Site2.Target(Site2, num, 2));

Page 18: Dlr

绑定中发生了什么? • 绑定主要由Binder完成 • 绑定在不同语言中是不同的,这里C#编译器使用了自己的

Binder • 绑定是昂贵的,结果会被缓存起来 • Target(L0) => CallSite(L1) =>Binder (L2)

• 动态类型的对象可以实现自己的绑定行为 • 这种动态行为通过实现IDynamicMetaObjectProvider来

告诉编译器 • 通常可以使用DynamicObject和ExpandoObject

Page 19: Dlr

ExpandoObject dynamic any = new ExpandoObject(); any.prop = 100; any.prop = "hello"; any.action = new Func<int>(() => { return 99 + 1; }); Console.WriteLine(any.action()); foreach (var member in (IDictionary<String, Object>)any) { Console.WriteLine(member.Key + ": " + member.Value); }

Page 20: Dlr

ExpandoObject ((INotifyPropertyChanged) any).PropertyChanged += delegate(object sender, PropertyChangedEventArgs e) { Console.WriteLine("属性{0} 已更改", .PropertyName); }; any.name = "某"; any.age = 30; any.email = "[email protected]";

Page 21: Dlr

Method Missing users.getByMail(“[email protected]”) 自动从用户表中找到Mail为[email protected]的用户 在C#中通过继承DynamicObject,并override其方法来实现具体行为。 • TryGetMember

• TrySetMember

• TryDeleteMember

• TryInvokeMember

• TryConvert

• TryCreateInstance

• TryInvoke

• TryBinaryOperation

• TryUnaryOperation

• TryGetIndex

• TrySetIndex

• TryDeleteIndex

• GetDynamicMemberNames

Page 22: Dlr

Method Missing public class AnyDynamicObject : DynamicObject

{

public override bool TryGetMember(GetMemberBinder binder, out object result)

{

Console.WriteLine("Shit happens,{0}属性被调用了", binder.Name);

result = "no value";

return true;

}

public override bool TrySetMember(SetMemberBinder binder, object value)

{

Console.WriteLine("Shit happens,{0}属性被赋值了", binder.Name);

return true;

}

}

Page 23: Dlr

Method Missing

dynamic any = new AnyDynamicObject();

Console.WriteLine(any.name);

any.age = 100;

Shit happens,name属性被调用了 no value Shit happens,age属性被赋值了

Page 24: Dlr

调用Python引擎

引用: IronPython.dll IronPython.Modules.dll Microsoft.Dynamic.dll Microsoft.Scripting.dll

example.py :

def addPrice(x, y): return x + y class User(object):

def __init__(self, name, email): self.Name = name self.AEmail = email def say(self):

print "hello" bob = User("bob", "[email protected]")

Page 25: Dlr

调用Python引擎 ScriptEngine pyEngine = IronPython.Hosting.Python.CreateEngine();

ScriptScope scope = pyEngine.ExecuteFile("example.py");

Func<dynamic, dynamic, int> add = scope.GetVariable("add");

Console.WriteLine(add(2,5));

dynamic bob = scope.GetVariable("bob");

Console.WriteLine(bob.Name);

bob.say();

7 bob hello

Page 26: Dlr

为什么Dynamic不能拯救世界

Page 27: Dlr

谁真正需要Dynamic/DLR • 轻量级ORM • MSBuild • 模板引擎 • 解释器/表达式引擎 • 编译正则表达式 • 调用COM • 替代Reflection.Emit的其它场合 • 构建DSL (Antlr + DLR)

Page 29: Dlr

Reference IronJS: https://github.com/fholm/IronJS

DLR应用案例: https://github.com/IronLanguages/main/wiki/IronLanguage-usages

浏览器中体验IronPython编程: http://www.trypython.org/

浏览器中使用Python代替Javascript: http://visitmix.com/labs/gestalt/

Page 30: Dlr