C#高级编程9-第12章 动态语言扩展
dynamic t = new ExpandoObject(); t.Abc = "abc"; t.Value = 10000; Console.WriteLine(t.Abc); t.Abc = "123"; Console.WriteLine(t.Abc);
dynamic动态类型的值是可读可写的,它是编译型语言,而Javascript是解释性语言.因此JavaScript定义后可以引用它。而dynamic定义后,无法引用它,无法获知它的类型是什么.只有编译运行时才能获得它的类型.
因此当我们无法获知它的类型时就会出现未知的异常,比如说类型转换异常、序列化异常、对象或属性不存在等等。因此对于使用dynamic时常常需要处理系统异常。
对于dynamic动态类型,它仅仅是一种类型,对于var类型它可以是一种序列化的字符串.
dynamic t = new ExpandoObject(); t.Abc = "abc"; t.Value = 10000; Console.WriteLine(t.Abc); t.Abc = "123"; Console.WriteLine(t.Abc); Console.WriteLine(t.ToString()); var t2 = new { Abc = "abc", Value = 10000 }; Console.WriteLine(t2.ToString());
对于var而言它可以声明后立即使用它,但是它的优点是如果var声明的成员它是只读的。但是声明成员值是可以修改的.
var t2 = new { Abc = "abc", Value = new { Item= new Person() } };
对于dynamic 而言,它声明后也可以立即使用它,它的成员可读可写,但是它是没有类型的需要编码者判断其来源和属性。
DynamicObejct 是所有动态类的基类,可以从其继承以实现自己的动态对象。ExpandoObject 是一个sealed 类,已经封装好了所有方法。
static void Main(string[] args) { dynamic dynamicObject = new MyDynamicObject(); dynamicObject.FirstName = "Alan"; dynamicObject.LastName = "Yang"; dynamicObject.Age = 28; Action<dynamic> show = (item) => Console.WriteLine("My name is " + item.FirstName + " " + item.LastName + ". I'm " + item.Age + " years old."); dynamicObject.Show = show; dynamicObject.Show(dynamicObject); Console.Read(); } public class MyDynamicObject : DynamicObject { Dictionary<string, object> _dynamicData = new Dictionary<string, object>(); public override bool TryGetMember(GetMemberBinder binder, out object result) { bool success = false; result = null; if (_dynamicData.ContainsKey(binder.Name)) { result = _dynamicData[binder.Name]; success = true; } else { result = "Property Not Found!"; success = false; } return success; } public override bool TrySetMember(SetMemberBinder binder, object value) { _dynamicData[binder.Name] = value; return true; } public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { result = true; dynamic method = _dynamicData[binder.Name]; method(args[0]); return true; } }
ExpandoObject
static void Main(string[] args) { dynamic dynamicObject = new ExpandoObject(); dynamicObject.FirstName = "Alan"; dynamicObject.LastName = "Yang"; dynamicObject.Age = 28; Action<dynamic> show = (item) => Console.WriteLine("My name is " + item.FirstName + " " + item.LastName + ". I'm " + item.Age + " years old."); dynamicObject.Show = show; dynamicObject.Show(dynamicObject); Console.Read(); }
ViewBag
public dynamic ViewBag { get { if (_dynamicViewData == null) { _dynamicViewData = new DynamicViewDataDictionary(() => ViewData); } return _dynamicViewData; } }
DynamicViewDataDictionary 类的定义为:
using System.Collections.Generic; using System.Diagnostics; using System.Dynamic; namespace System.Web.Mvc { internal sealed class DynamicViewDataDictionary : DynamicObject { private readonly Func<ViewDataDictionary> _viewDataThunk; public DynamicViewDataDictionary(Func<ViewDataDictionary> viewDataThunk) { _viewDataThunk = viewDataThunk; } private ViewDataDictionary ViewData { get { ViewDataDictionary viewData = _viewDataThunk(); Debug.Assert(viewData != null); return viewData; } } // Implementing this function improves the debugging experience as it provides the debugger with the list of all // the properties currently defined on the object public override IEnumerable<string> GetDynamicMemberNames() { return ViewData.Keys; } public override bool TryGetMember(GetMemberBinder binder, out object result) { result = ViewData[binder.Name]; // since ViewDataDictionary always returns a result even if the key does not exist, always return true return true; } public override bool TrySetMember(SetMemberBinder binder, object value) { ViewData[binder.Name] = value; // you can always set a key in the dictionary so return true return true; } } }