动态对象
动态语言运行时DLR
允许添加动态语言,使得C#可以支持动态语言的功能。
关于DLR的库在下列两个命名空间中
System.Dynamic;
System.Runtime.CompilerServices;目前有IronPython,IronRuby等支持DLR的开源版本
dynamic动态类型
动态类型在编译期间会忽略类型检查,并假定动态类型的一切操作都是有效的;
运行时可抛出RuntimeBinderException类型的异常。
与var的不同点:
var是延迟确定类型,一旦确定类型不能改变。
dynamic可以在运行期间改变类型,并可以改变多次。
dynamic类型有两个限制:
动态类型不支持扩展方法,lamda表达式不支持作为动态方法调用的参数。
LINQ不支持动态对象。
static void Main(string[] args)
{
//Console.WriteLine的参数是在运行时绑定
dynamic a;
a = 56;
Console.WriteLine(a);
Console.WriteLine(a.GetType());
a = "12345";
Console.WriteLine(a);
a = new { code = "12", age = 18 };
Console.WriteLine(a);
Console.ReadKey();
}
ScriptRuntime
可以在应用程序中迁入脚本。
下面的示例需要使用Nuget安装IronPython
using System;
using Microsoft.Scripting.Hosting;
using IronPython.Hosting;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
ScriptRuntime sr = Python.CreateRuntime();
ScriptEngine se = sr.GetEngine("python");
string content = "discCount=5\n" +
"discAmt=.1\n" +
"retAmt=amt\n" +
"if x>discCount:\n" +
" retAmt=amt-(amt*discAmt)\n";
ScriptSource ss = se.CreateScriptSourceFromString(content);
ScriptScope ssc = se.CreateScope();
ssc.SetVariable("amt", 10);
ssc.SetVariable("x", 20);
ss.Execute(ssc);
dynamic d = ssc.GetVariable("retAmt");
Console.WriteLine(d);
Console.ReadKey();
}
}
}
DynamicObject
下面定义了一个动态对象,可以在运行期间动态给对象添加成员;
重写了DynamicObject的TryGetMember、TrySetMember和TryInvokeMember方法,并用Dictionary保存新添加的成员;
DynamicObject类型的动态对象可以自由的控制成员的访问
class DyObj:DynamicObject
{
private Dictionary<string, object> dyProperty = new Dictionary<string, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if(dyProperty.ContainsKey(binder.Name))
{
result = dyProperty[binder.Name];
return true;
}
else
{
result = binder.Name + "成员不存在";
return false;
}
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
dyProperty[binder.Name] = value;
return true;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
dynamic method = dyProperty[binder.Name];
result = method((int)args[0],(int)args[1]);
return true;
}
}
class Program
{
static void Main(string[] args)
{
dynamic dyObj = new DyObj();
dyObj.Name = "zhangsan";
dyObj.Age = 18;
Console.WriteLine(dyObj.GetType());
Console.WriteLine(dyObj.Name);
Console.WriteLine(dyObj.Age);
Func<int, int, int> func = (i, j) => i + j;
dyObj.Add = func;
int k = dyObj.Add(5, 6);
Console.WriteLine(k);
Console.ReadKey();
}
}
ExpandoObject
下面这段代码把DyObj换成了ExpandoObject,效果是一样的;使用ExpandoObject不需要重写方法就可以动态给对象添加成员。
不需要精准控制成员的访问可以使用ExpandoObject。
class Program
{
static void Main(string[] args)
{
dynamic dyObj = new ExpandoObject();
dyObj.Name = "zhangsan";
dyObj.Age = 18;
Console.WriteLine(dyObj.GetType());
Console.WriteLine(dyObj.Name);
Console.WriteLine(dyObj.Age);
Func<int, int, int> func = (i, j) => i + j;
dyObj.Add = func;
int k = dyObj.Add(5, 6);
Console.WriteLine(k);
dyObj.Skill = new List<string>();
dyObj.Skill.Add("java");
dyObj.Skill.Add("C#");
dyObj.Skill.Add("C");
foreach (string skill in dyObj.Skill)
Console.WriteLine(skill);
Console.ReadKey();
}
}