Skip to content

.NET Core 实战 [No.236~240] 动态类型

🏷️ 《.NET Core 实战》

使用 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 类提供了一系列虚方法可以供开发者重写,比较重要的是以下两个虚方法。

  1. TryGetMember 类似于属性的 getter 方法,在读取字段值时调用。
  2. 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 个精彩案例》 -- 周家安 著