什么是动态类型
了解什么是动态类型首先我们了解静态类型,在我们平时定义一个int i=1就是静态类型,静态类型就是我们在没有编译的时候已经明确的知道他是一个int类型,动态语言是我们在运行时才会知道的类型。所以我们在编写动态类型的时候是无法使用vs的智能提示,因为编译器也不知道他是一个什么类型。
dynamic i = 1;
Console.WriteLine(i.GetType());
dynamic str = "1";
Console.WriteLine(str.GetType());
引用一张结构图
从图中可以看出,DLR是建立在CLR的基础之上的,其实动态语言运行时是动态语言和C#编译器用来动态执行代码的库,它不具有JIT编译,垃圾回收等功能。DLR通过它的绑定器(binder)和 调用点(callsite),元对象来把代码转换为表达式树,然后再把表达式树编译为IL代码,最后 由CLR编译为本地代码(DLR就是帮助C#编译器来识别动态类型)。
dynamic和var区别
var关键字不过是一个指令,它告诉编译器根据变量的初始化表达式来 推断类型。(记住var并不是类型),而dynamic是类型,但是编译时不属于CLR 类型(指的int,string,bool,double等类型,运行时肯定CLR类型中一种的),它是包含了 System.Dynamic.DynamicAttribute特性的System.Object类型,但与object又不一样,不一样主要体现在动态类型不会在编译时时执行显式转换
使用动态类型的优点
1.减少强类型的转换
2.延迟加载
3.调用C#类型中不存在的其他语言的类型
使用动态类型的缺点
1.没有智能提示
2.需要预先知道接收的数据结构
动态语言的约束
1不能用动态类型作为扩展方法的参数
2委托和动态类型不能隐式转换
3动态类型不能调用构造函数和静态方法
4类型声明和泛型类型参数
5类型声明和泛型类型参数不能声明一个基类为dynamic的类型,也不能将dynamic用于类型参数的约束,或作为类型 所实现的接口的一部分
实现动态行为
我们实现动态行为微软给我们提供了三种方式,下面我们来试一试:
使用ExpandObject
static void Main(string[] args)
{
dynamic expand = new ExpandoObject();
//动态为expand类型绑定属性
expand.Name = "王麻子";
expand.Age = 24;
//动态为expand类型绑定方法
expand.AddMethod = (Func<int, string>)(x => $"你传进来的是{x}");
//调用expand类型的属性和方法
Console.WriteLine($"姓名:{expand.Name}\n年龄:{expand.Age}\n绑定方法:{expand.AddMethod(666)}");
Console.Read();
}
姓名:王麻子
年龄:24
绑定方法:你传进来的是666
使用DynamicObject
class DynamicType : DynamicObject
{
// 重写方法,
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
Console.WriteLine(binder.Name + "方法被调用");
result = null;
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
Console.WriteLine(binder.Name + "属性被设置," + "设置的值为:" + value);
return true;
}
}
class Program
{
static void Main(string[] args)
{
dynamic dynamicobj = new DynamicType();
dynamicobj.CallMethod();
dynamicobj.Name = "王麻子";
dynamicobj.Age = "24";
Console.Read();
}
}
CallMethod方法被调用
Name属性被设置,设置的值为:王麻子
Age属性被设置,设置的值为:24
实现IDynamicMetaObjectProvider接口
class Metadynamic : DynamicMetaObject
{
internal Metadynamic(Expression expression, DynamicType2 value) : base(expression, BindingRestrictions.Empty, value) { }
//重写响应成员调用方法
public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
{
//获得真正的对象
DynamicType2 target = (DynamicType2)base.Value;
Expression self = Expression.Convert(base.Expression, typeof(DynamicType2));
var restrictions = BindingRestrictions.GetInstanceRestriction(self, target);
//输出绑定方法名
Console.WriteLine(binder.Name + "方法被调用了");
return new DynamicMetaObject(self, restrictions);
}
}
public class DynamicType2 : IDynamicMetaObjectProvider
{
public DynamicMetaObject GetMetaObject(Expression parameter)
{
Console.WriteLine("开始获得元数据......");
return new Metadynamic(parameter, this);
}
}
class Program
{
static void Main(string[] args)
{
dynamic dynamicobj2 = new DynamicType2();
dynamicobj2.Call();
Console.Read();
}
}
开始获得元数据......
Call方法被调用了