dynamic基础类型/C#与动态脚本语言交互/dynamic自定义类型

ruby python js动态语言有他们自身的优点,因此C#中的var关键字和匿名方法开辟了C#的动态编程路径,.net 4中增加了dynamic类型。
DLR(dynamic language runtime)是脚本运行库,是添加到CLR的一系列服务,它允许添加动态语言,如ruby python,并使C#具有这些动态语言相同的某些动态功能,silverlight也使用DLR。DLR位于System.Dynamic和System.Rumtime.Complier-Services几个类中。
 DLR脚本运行库允许给脚本传入变量和从脚本传出变量。

一、使用dynamic类型

1.dynamic动态类型,运行时候才会检查动态类型对象及对象上的方法


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ErrorExample
{
class Program
{
    static void Main(string[] args)
    {
        var staticPerson = new Person();
        dynamic dynamicPerson = new Person();
        //staticPerson.GetFullName("John", "Smith");//
        dynamicPerson.GetFullName("John", "Smith");
 // 编译期间不会报错,运行时候才检查报错
    }
}

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string GetFullName()
    {
        return string.Concat(FirstName, " ", LastName);
    }
}
}

2.  dynamic类型,可以在运行期间改变类型

  dynamic dyn;
 // 声明为var会报错,var只是编译时候绑定,绑定后就不能变了
            dyn = 100;
            Console.WriteLine(dyn.GetType());
            Console.WriteLine(dyn);

            dyn = "This is a string";
            Console.WriteLine(dyn.GetType());
            Console.WriteLine(dyn);

            dyn = new Person() { FirstName = "Bugs", LastName = "Bunny" };
            Console.WriteLine(dyn.GetType());
            Console.WriteLine("{0} {1}", dyn.FirstName, dyn.LastName);


3.dynamic类型限制
1)不支持拓展方法中使用dynamic类型。
2)匿名函数(lambda表达式)也不能用作动态类型的方法调用的参数。
后台编译时候需要指定运行时期语法语义检查的类来检查,然后生成表达式树,来缓存。显然dynamic类型可以做到动态类型但是是有性能代价的,因为c#本身是静态即时编译类型的语言。

二.利用DLR ScriptRuntime和脚本交互

利用系统提供了python,ruby,js类型的脚本语言的 scriptRuntime脚本运行库引擎。
C#中直接使用,从脚本中获取脚本对象,然后给脚本对象传入值,利用脚本对象计算的返回值赋值给C#中变量就可以了。例如:
string scrptFile = "CountDisc.py";
ScriptRuntime scriptRuntime = ScriptRuntime.CreateFromConfiguration();
ScriptEngine pythEng = scriptRuntime.GetEngine("Python");
ScriptSource source = pythEng.CreateScriptSourceFromFile(scrptFile);
ScriptScope scope = pythEng.CreateScope();
scope.SetVariable("prodCount", Convert.ToInt32(totalItems.Text));
source.Execute(scope);
label5.Content = scope.GetVariable("retAmt").ToString();
简化调用的实例:

ScriptRuntime scriptRuntime = ScriptRuntime.CreateFromConfiguration();
dynamic calcRate = scriptRuntime.UseFile("CalcTax.py");
label5.Content = calcRate.CalcTax(Convert.ToDecimal(label5.Content)).ToString();

三、定义自己的动态类型-动态添加属性和方法

dynamic修饰的动态类型都是基本类型,如果要修饰自己的动态类型,且动态类型可以动态的添加属性和方法。
那么自定义的动态类型,需要继承自DynamicObject或ExpandoObject类。
继承自DynamicObject需要重写了3个方法:
 public override bool TryGetMember(GetMemberBinder binder, out object result)
 public override bool TrySetMember(SetMemberBinder binder, object value)
 public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
且这些重载的方法,都是.net帮助调用的,在使用时候只是简单的为类添加属性和方法。
例如:
using System;
using System.Dynamic;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
namespace Dynamic
{
    class Program
    {
        static void Main(string[] args)
        {
            dynamic dyn;
            dyn = 100;
            Console.WriteLine(dyn.GetType());
            Console.WriteLine(dyn);

            dyn = "This is a string";
            Console.WriteLine(dyn.GetType());
            Console.WriteLine(dyn);

            dyn = new Person() { FirstName = "Bugs", LastName = "Bunny" };
            Console.WriteLine(dyn.GetType());
            Console.WriteLine("{0} {1}", dyn.FirstName, dyn.LastName);

            dyn = new WroxDynamicObject();
            dyn.FirstName = "Bugs";
            dyn.LastName = "Bunny";
            Console.WriteLine(dyn.GetType());
            Console.WriteLine("{0} {1}", dyn.FirstName, dyn.LastName);

            dyn.MiddleName = "Rabbit";
            Console.WriteLine(dyn.MiddleName);
            Console.WriteLine(dyn.GetType());
            Console.WriteLine("{0} {1} {2}", dyn.FirstName, dyn.MiddleName, dyn.LastName);

            List<Person> friends = new List<Person>();
            friends.Add(new Person() { FirstName = "Daffy", LastName = "Duck" });
            friends.Add(new Person() { FirstName = "Porky", LastName = "Pig" });
            friends.Add(new Person() { FirstName = "Tweety", LastName = "Bird" });
            dyn.Friends = friends;
            foreach (Person friend in dyn.Friends)
            {
                Console.WriteLine("{0} {1}", friend.FirstName, friend.LastName);
            }

            Func<DateTime, string> GetTomorrow = today => today.AddDays(1).ToShortDateString();
            dyn.GetTomorrowDate = GetTomorrow;
            Console.WriteLine("Tomorrow is {0}", dyn.GetTomorrowDate(DateTime.Now));

            DoExpando();
            Console.Read();
        }

        static void DoExpando()
        {
            dynamic expObj = new ExpandoObject();
            expObj.FirstName = "Daffy";
            expObj.LastName = "Duck";
            Console.WriteLine(expObj.FirstName + " " + expObj.LastName);
            Func<DateTime, string> GetTomorrow = today => today.AddDays(1).ToShortDateString();
            expObj.GetTomorrowDate = GetTomorrow;
            Console.WriteLine("Tomorrow is {0}", expObj.GetTomorrowDate(DateTime.Now));

            expObj.Friends = new List<Person>();
            expObj.Friends.Add(new Person() { FirstName = "Bob", LastName = "Jones" });
            expObj.Friends.Add(new Person() { FirstName = "Robert", LastName = "Jones" });
            expObj.Friends.Add(new Person() { FirstName = "Bobby", LastName = "Jones" });

            foreach (Person friend in expObj.Friends)
            {
                Console.WriteLine(friend.FirstName + "  " + friend.LastName);
            }
        }
    }

    class WroxDynamicObject : 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!";

            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)
        {
            dynamic method = _dynamicData[binder.Name];
            result = method((DateTime)args[0]);
            return result != null;            
        }
    }
}
创建自定义类型对象DynamicObject或ExpandoObject,与基本类型区别。
1.不能创建dynamic的自定义类型的空对象,必须赋予某个继承自DynamicObject或是ExpandoObject类型对象。
2.创建dynamic的自定义类型对象不能一开始赋予给基础类型。
如果需要控制动态对象中的属性的添加和访问,则使该对象派生自DynamicObject是最佳选择。
使用DynamicObject可以重写介个方法,准确的控制对象与运行库的交互方式。其它情况就应该使用ExpandoObject类型,或dynamic基础类型。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值