VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > Objective-C编程 >
  • c#4.01之Dynamic 2

制作者:剑锋冷月 单位:无忧统计网,www.51stat.net
 

  .NET 4.0 通过嵌入 DLR Runtime 来实现对动态编程的支持。DLR Runtime 包含 Expression Trees、CallSite Caching、Dynamic Object Interoperability 几个子系统。某些实现部分,我们在前一章分析 dynamic 关键字时已有所接触。

  动态编程行为主要两个部分:

  动态访问对象: 这也就是 dynamic 所要做的主要工作,我们可以在运行时 "动态" 访问对象成员,而不是编译期。

  创建动态对象: 我们可以在运行期定义对象的行为,包括增删对象成员等。想必大家对动态语言的 OpenClass 已经神往已久了。

  我们试着创建一些 .NET 4.0 动态调用的例子。和前一章 "动态" 调用 "静态对象成员" 不同,下面这些例子着重于 "动态对象"。

class MyClass : DynamicObject
{
  private Dictionary<string, object> values = new Dictionary<string, object>();
  public override bool TryGetMember(GetMemberBinder binder, out object result)
  {
    result = null;
    if (!values.ContainsKey(binder.Name)) return false;
    result = values[binder.Name];
    return true;
  }
  public override bool TrySetMember(SetMemberBinder binder, object value)
  {
    values[binder.Name] = value;
    return true;
  }
  public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
  {
    switch (binder.Name)
    {
      case "Test":
        var sb = new StringBuilder();
        for (int i = 0; i < binder.CallInfo.ArgumentCount; i++)
        {
          sb.AppendFormat("{0}={1}\r\n", binder.CallInfo.ArgumentNames[i], args[i]);
        }
        result = sb.ToString();
        return true;
      default:
        result = null;
        return false;
    }
  }
}
class Program
{
  static void Main(string[] args)
  {
    dynamic o = new MyClass();
    o.X = 123;
    o.Y = "Hello, World!";
    var s = o.Test(A: 123, Y: "abc");
    Console.WriteLine(o.X);
    Console.WriteLine(o.Y);
    Console.WriteLine(s);
  }
}

 

  输出:

123
Hello, World!
A=123
Y=abc

  由于 DynamicObject 默认没有实现操作,因此在上面例子中我们得自己折腾。

public class DynamicObject : IDynamicMetaObjectProvider
{
  public virtual bool TryGetMember(GetMemberBinder binder, out object result)
  {
    result = null;
    return false;
  } 
  ... ...
}

  当然,如果嫌麻烦,可以考虑用下面这种方式。

dynamic o = new ExpandoObject();
o.Test = new Func<int, string, string>((a, y) => String.Format("A={0}\r\nY={1}", a, y));
o.X = 123;
o.Y = "Hello, World!";
var s = o.Test(123, "abc");
Console.WriteLine(o.X);
Console.WriteLine(o.Y);
Console.WriteLine(s);

  和 javascript、Python 之类的动态语言很像吧。我们还可以对其成员进行增删和遍历操作,还记得 Python 中的 dir() 吧。

dynamic o = new ExpandoObject();
o.Test = new Func<int, string, string>((a, y) => String.Format("A={0}\r\nY={1}", a, y));
o.X = 123;
o.Y = "Hello, World!";
// 遍历成员
var dict = o as IDictionary<string, object>;
Console.WriteLine(String.Join(", ", dict.Keys));
// 移除成员
dict.Remove("Y");
try
{
  Console.WriteLine(o.Y);
}
catch (RuntimeBinderException ex)
{
  Console.WriteLine(ex.Message);
}

 

  DynamicObject 和 ExpandoObject 都实现了 IDynamicMetaObjectProvider 接口,这是 DLR 进行动态操作所必须的。

public class DynamicObject : IDynamicMetaObjectProvider
{
  // Methods
  protected DynamicObject();
  public virtual IEnumerable<string> GetDynamicMemberNames();
  public virtual DynamicMetaObject GetMetaObject(Expression parameter);
  public virtual bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result);
  public virtual bool TryConvert(ConvertBinder binder, out object result);
  public virtual bool TryCreateInstance(CreateInstanceBinder binder, object[] args, out object result);
  public virtual bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes);
  public virtual bool TryDeleteMember(DeleteMemberBinder binder);
  public virtual bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result);
  public virtual bool TryGetMember(GetMemberBinder binder, out object result);
  public virtual bool TryInvoke(InvokeBinder binder, object[] args, out object result);
  public virtual bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result);
  public virtual bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value);
  public virtual bool TrySetMember(SetMemberBinder binder, object value);
  public virtual bool TryUnaryOperation(UnaryOperationBinder binder, out object result);
}
 
public sealed class ExpandoObject : IDynamicMetaObjectProvider, IDictionary<string, object>, 
  ICollection<KeyValuePair<string, object>>, IEnumerable<KeyValuePair<string, object>>, 
  IEnumerable, INotifyPropertyChanged
{
  // Events
  event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged;
  // Methods
  public ExpandoObject();
  void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> item);
  void ICollection<KeyValuePair<string, object>>.Clear();
  bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> item);
  void ICollection<KeyValuePair<string, object>>.CopyTo(KeyValuePair<string, object>[] array, int arrayIndex);
  bool ICollection<KeyValuePair<string, object>>.Remove(KeyValuePair<string, object> item);
  void IDictionary<string, object>.Add(string key, object value);
  bool IDictionary<string, object>.ContainsKey(string key);
  bool IDictionary<string, object>.Remove(string key);
  bool IDictionary<string, object>.TryGetValue(string key, out object value);
  IEnumerator<KeyValuePair<string, object>> IEnumerable<KeyValuePair<string, object>>.GetEnumerator();
  IEnumerator IEnumerable.GetEnumerator();
  
  DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter);
  // Properties
  int ICollection<KeyValuePair<string, object>>.Count { get; }
  bool ICollection<KeyValuePair<string, object>>.IsReadOnly { get; }
  object IDictionary<string, object>.this[string key] { get; set; }
  ICollection<string> IDictionary<string, object>.Keys { get; }
  ICollection<object> IDictionary<string, object>.Values { get; }
}

 

  DynamicObject 集中实现成员调用,可以更灵活地调度。而 ExpandoObject 则更轻便,更接近于动态语言编程习惯。

 

 

  输出:

123
Hello, World!
A=123
Y=abc

  由于 DynamicObject 默认没有实现操作,因此在上面例子中我们得自己折腾。

public class DynamicObject : IDynamicMetaObjectProvider
{
  public virtual bool TryGetMember(GetMemberBinder binder, out object result)
  {
    result = null;
    return false;
  } 
  ... ...
}

  当然,如果嫌麻烦,可以考虑用下面这种方式。

dynamic o = new ExpandoObject();
o.Test = new Func<int, string, string>((a, y) => String.Format("A={0}\r\nY={1}", a, y));
o.X = 123;
o.Y = "Hello, World!";
var s = o.Test(123, "abc");
Console.WriteLine(o.X);
Console.WriteLine(o.Y);
Console.WriteLine(s);

  和 javascript、Python 之类的动态语言很像吧。我们还可以对其成员进行增删和遍历操作,还记得 Python 中的 dir() 吧。

dynamic o = new ExpandoObject();
o.Test = new Func<int, string, string>((a, y) => String.Format("A={0}\r\nY={1}", a, y));
o.X = 123;
o.Y = "Hello, World!";
// 遍历成员
var dict = o as IDictionary<string, object>;
Console.WriteLine(String.Join(", ", dict.Keys));
// 移除成员
dict.Remove("Y");
try
{
  Console.WriteLine(o.Y);
}
catch (RuntimeBinderException ex)
{
  Console.WriteLine(ex.Message);
}


相关教程