.NET Core 实战 [No.236~240] 动态类型
使用 dynamic
关键字可以用来声明动态类型。ExpandoObject
是专为动态类型封装的类型。
csharp
dynamic dx = new System.Dynamic.ExpandoObject();
dx.Message = "Hello";
dx.Name = "World";
Console.WriteLine($"{dx.Message}, {dx.Name}!"); // Hello, World!
注意
编码时不会出现属性列表的智能提示。
在编译期间不会解析动态对象,也不会验证成员名称是否正确。如果成员名称输错了,只有运行时才会报错。
由于 ExpandoObject
类实现了 IDictionary<string, object>
接口,所以可以以字典的形式访问其对象。
csharp
IDictionary<string, object> dic = dx;
foreach (var item in dic)
{
Console.WriteLine($"{item.Key} : {item.Value}");
}
// Message : Hello
// Name: World
当框架提供的动态类型方案无法满足时,开发者可以从 DynamicObject
类派生出自定义的动态类型。 DynamicObject
类提供了一系列虚方法可以供开发者重写,比较重要的是以下两个虚方法。
- TryGetMember 类似于属性的 getter 方法,在读取字段值时调用。
- TrySetMember 类似于属性的 setter 方法,在对字段赋值时调用。
csharp
class CustomDynamicObject : DynamicObject
{
private IDictionary<string, object> _data = new Dictionary<string, object>();
// getter 方法
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
return _data.TryGetValue(binder.Name.ToLower(), out result);
}
// setter 方法
public override bool TrySetMember(SetMemberBinder binder, object value)
{
return _data.TryAdd(binder.Name.ToLower(), value);
}
}
csharp
dynamic cd = new CustomDynamicObject();
cd.Year = 2020;
Console.WriteLine($"Year = {cd.Year}"); // Year = 2020
开发者可以在自定义的动态类型上直接定义成员(字段、属性、方法等)。运行时会优先查找并解析类中已定义的成员。
csharp
class CustomDynamicObject : DynamicObject
{
// 明确定义的属性
public string Name { get; set; }
}
通过重写 TryInvoke 方法可以模拟委托类型的调用方法。
csharp
class CustomDynamicObject : DynamicObject
{
// 模拟委托实例调用
public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
{
result = 0;
int temp = 0;
foreach (var n in args.Cast<int>())
{
temp += n;
}
result = temp;
return true;
}
}
调用方式如下:
csharp
dynamic d = new CustomDynamicObject();
int result = d(90, 1, 18);
Console.WriteLine($"d(90, 1, 18) = {result}"); // d(90, 1, 18) = 109
参考:《.NET Core 实战:手把手教你掌握 380 个精彩案例》 -- 周家安 著