DLR (Dynamic Language Runtime)
数值类型统一用法
static dynamic Plus(Dynamic x, dynamic y) => (x + y)/2
动态成员重载解析
以动态类型参数调用静态已知的方法会将方法重载的解析从编译时推迟到运行时
-
简化的访问者模式
1 class ToXElementPresonVisitor 2 { 3 //DyanmicVisit根据所传递参数带类型,决定所使用方法是Persion或者Customers、Employee 4 public XElement DynamicVisit (Person p) => Visit((dynamic) p); 5 6 XELement Visit(Person p){ 7 8 } 9 10 XElement Visit(Customers c){ 11 12 } 13 14 XElemnt Visit(Employee e){} 15 }
利用方法重载的延后编译,可以根据参数类型调用选择调用方法
-
支持重载的方式(多重分派)
单分派
C#与CLR的虚方法对动态性的支持,重载的解析执行在编译的时候,须由编译器理解
多分派
动态调用的解析,在运行时执行
-
调用未知类型的泛型类型成员
1 static void Write(dynamic obj) 2 { 3 object result = GetFooValue(object); 4 if(result != null) Console.WirteLine(result); 5 } 6 static T GetFooValue<T>(Foo<T> foo) => foo.Value; 7 static object GetFooValue(object foo) => null;
接受object参数的重载GetFooValue方法可以作为任何参数类型的后备方法
如果待定对象并非基于<T>,则C#的动态绑定器将选定以object为参数的重载,而不抛出异常
自定义绑定(实现动态对象)
-
DynamicObject
IDynamicMetaObjectProvider 接口提供语义绑定
RuntimerBinderException 抛出绑定失败异常
一个比较有意思的应用
结合拓展类型,拓展使用动态访问对象
1 static void Main() 2 { 3 var oneBook = new Book(); 4 //price 为dynamic动态类型 5 var price = oneBook.DynamicAttribtes().Price; 6 Console.WriteLine(string.Format("取值结果,书本价格{0}", (int)price)); 7 oneBook.DynamicAttribtes().Price = 123; 8 var deliveryDate = oneBook.DynamicAttribtes().GetDelivery(); 9 10 //控制台输出 11 //Hello World! 12 //尝试从Price取值 13 //取值结果,书本价格5 14 //尝试给Price赋值 15 //尝试调用动态方法,没有实现该方法 16} 17 18 19 public class Book 20 { 21 public string Name; 22 23 public string Author; 24 } 25 /// <summary> 26 /// 书籍拓展类 27 /// </summary> 28 static class BookExtension 29 { 30 /// <summary> 31 /// 获取数据的带动态数据 32 /// </summary> 33 /// <param name="b"></param> 34 /// <returns></returns> 35 public static dynamic DynamicAttribtes(this Book b) => new BookWrapper(b); 36 37 class BookWrapper : DynamicObject 38 { 39 Book _book; 40 41 public BookWrapper(Book book) 42 { 43 _book = book; 44 } 45 46 public override bool TryGetMember(GetMemberBinder binder, out object result) 47 { 48 result = 5; 49 Console.WriteLine(string.Format("尝试从{0}取值", binder.Name)); 50 return true; 51 } 52 53 public override bool TrySetMember(SetMemberBinder binder, object value) 54 { 55 Console.WriteLine(string.Format("尝试给{0}赋值",binder.Name)); 56 return true; 57 } 58 59 public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) 60 { 61 result = ""; 62 Console.WriteLine("尝试调用动态方法,没有实现该方法"); 63 return true; 64 } 65 } 66 }
- ExpandoObject
一个已经实现的简单的动态类,使用字符串获存储和检索对象
dynamic x = new ExpandoObject();
x.BookName = "C# 从入门到放弃";
x.Price = 99;
Console.WriteLine(x.BookName);
Console.WriteLine(x.Price);
虽支持dynamic,但无法在运行时执行字符串中描述的表达式
可以直接使用动态语言的API(例如Python)
1 using Micorsoft.Scripting 2 3 ScriptEnging engine = Python.CreateEnging();