您的位置:首页 > 编程语言 > C#

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

2015-10-10 10:58 507 查看
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基础类型。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: