65.9K
CodeProject 正在变化。 阅读更多。
Home

在 C# 中创建一个简单的动态字典

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.86/5 (8投票s)

2020 年 5 月 13 日

MIT

2分钟阅读

viewsIcon

38248

downloadIcon

277

本文档展示了如何创建一个类似于 JavaScript 的动态“对象”,用于在网页和 T4 模板中使用。

使用 ExpandoObject 更好:我曾以为它在 .NET 1.x 中已被弃用 - 我弄错了

引言

JavaScript 允许通过简单地将值赋给任意字段来创建对象,从而动态创建它们。在 C# 中没有直接的等效方法。但是,借助 .NET DLR,我们可以创建一个。这可以在某些情况下提供更易读的字段访问,而否则会使用字典。

概念化这个混乱的局面

使用 Dictionary 类,可以通过键获取或设置值,但如果在 ASP.NET 页面中使用它们,可能会有些笨拙。

<%= obj["foo"] %>

我们真正想要的是

<%= obj.foo %>

通常,C# 会要求您使用强类型对象代替字典,但这有两个显著缺点:首先是需要编写额外的代码。其次是无法添加任意字段。

我们将创建一个简单的“对象”,它由一个带有 string 键的字典支持。它将通过也允许使用字段访问语法来访问这些名称/值来解决此问题。

你已经知道优点,但这种方法也有缺点,表现为性能略低于字典以及缺乏编译时类型检查。您应该在某些情况下使用它来提高可读性,而否则会使用字典。

编写这个混乱的程序

由于你已经知道如何从上面使用它,我们将重点介绍我是如何创建它的。这里的想法很简单。我们从 DynamicObject 派生,然后在它之上实现一个字典接口。所有这些都只是重写 TryGetMember()TrySetMember() 并委托给内部字典。字典成员也转发到内部字典。一切都非常简单。我不会显示所有代码,但我会显示使 DynamicDictionary 魔法起作用的部分

public override bool TryGetMember(GetMemberBinder binder, out object result)
{
    T res;
    if (_inner.TryGetValue(binder.Name, out res))
    {
        result = res;
        return true;
    }
    result = null;
    return false;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
    _inner[binder.Name] = (T)value;
    return true;
}

其中 T 上面是字典保存的值的类型 - 键始终是字符串。

使用它很简单,并且已经在上面描述过,但这里有一些示例代码 - 包含的项目中还有更多,包括一个 T4 模板用于演示目的

// set some values
dynamic obj = new DynamicDictionary<object>();
obj.test1 = "foo";
obj["test2"] = "bar";
obj.test3 = 100;

// get some values
Console.WriteLine("test1 = " + obj.test1);
Console.WriteLine("test2 = " + obj["test2"]);
Console.WriteLine("test3 = " + obj["test3"]);

请注意,上面展示了作为动态对象和作为字典进行访问。这些对象支持两者,就像 JavaScript 一样。这里的魔法是 dynamic 关键字,它告诉 C# 编译器创建一个动态“调用站点”,其中成员访问是延迟绑定的 - 在运行时而不是编译时。现在你可以像往常一样访问对象,唯一的例外是没有 Intellisense(自动完成)在你的 IDE 中。

你可以在代码背后构造这些动态对象,然后在 ASP.NET 页面或 T4 模板中使用它们。

历史

  • 2020 年 5 月 13 日 - 初始提交
© . All rights reserved.