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






2.86/5 (8投票s)
本文档展示了如何创建一个类似于 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 日 - 初始提交