Upload
sharp-blade
View
1.329
Download
0
Embed Size (px)
Citation preview
Exploring DLR
江嘉诚
2011.8.28
关于我
• 江嘉诚 (无厚之刃)
• 华南理工大学
• 微博:@以无厚入有间 ( 典故参见《庄子》)
• 博客:http://sharp-blade.tuita.com/
DLR是
• Dynamic Language Runtime
• 由 IronPython 发起人Jim Hugunin开发
• 一个构建在CLR之上的运行时
• 在.Net上构建动态语言的标准体系
The DLR's mission is to enable an ecosystem of dynamic languages on .NET.
动态语言需要什么
• Lexer & Parser
• 交互式脚本引擎(REPL)
• 动态加载代码的能力
• 动态类型
• 元编程(自省/魔术方法/动态修改类型)
• 其它:Stackless/Actor/Continuation
DLR提供了什么
• 脚本语言引擎
• 可以在运行时编译的表达式树
• 延迟绑定
• 动态语言的互操作性
ExpressionTree
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”);
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
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;
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");
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);
代码即数据
数据即代码
Dynamic & Late Binding
Foo foo = new Foo(); foo.act();
dynamic foo = …… // new Foo() foo.act();
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))); }
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));
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))); }
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));
绑定中发生了什么? • 绑定主要由Binder完成 • 绑定在不同语言中是不同的,这里C#编译器使用了自己的
Binder • 绑定是昂贵的,结果会被缓存起来 • Target(L0) => CallSite(L1) =>Binder (L2)
• 动态类型的对象可以实现自己的绑定行为 • 这种动态行为通过实现IDynamicMetaObjectProvider来
告诉编译器 • 通常可以使用DynamicObject和ExpandoObject
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); }
ExpandoObject ((INotifyPropertyChanged) any).PropertyChanged += delegate(object sender, PropertyChangedEventArgs e) { Console.WriteLine("属性{0} 已更改", .PropertyName); }; any.name = "某"; any.age = 30; any.email = "[email protected]";
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
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;
}
}
Method Missing
dynamic any = new AnyDynamicObject();
Console.WriteLine(any.name);
any.age = 100;
Shit happens,name属性被调用了 no value Shit happens,age属性被赋值了
调用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]")
调用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
为什么Dynamic不能拯救世界
谁真正需要Dynamic/DLR • 轻量级ORM • MSBuild • 模板引擎 • 解释器/表达式引擎 • 编译正则表达式 • 调用COM • 替代Reflection.Emit的其它场合 • 构建DSL (Antlr + DLR)
Reference IronPython & IronRuby: https://github.com/IronLanguages
利用DLR + Antlr快速构建DSL: DLR - Build Your Own Language (without tears)
利用IronRuby开发WPF应用: http://www.infoq.com/cn/articles/ironruby-wpf
Iron语言相关书籍: IronPython in Action IronRuby Unleashed Graph#演示工具: http://graphsharp.codeplex.com/
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/