编程技术是改变世界的力量。
本站
当前位置:网站首页 > 后端语言 > 正文

C#动态类型ExpandoObject,DynamicObject和dynamic傻傻分不清

gowuye 2024-05-16 14:29 3 浏览 0 评论

在 C# 中,dynamic关键字、ExpandoObject 类和 DynamicObject 类是处理动态对象的主要方法。但是,ExpandoObject 和 DynamicObject 通常可以互换使用,因此很难区分它们。在本文中,我们将研究ExpandoObject,DynamicObject和dynamic之间的区别。我们将更好地理解这些概念以及如何在代码中有效地使用它们。

C# 中什么是dynamic

dynamic是一种 C# 静态类型。它在 C# 中被引入是为了在比如使用动态类型语言(如 Python)、使用 COM 对象、访问 HTML DOM 或使用 JSON 时提供互操作性(interoperability,互操作性一般指两种不同语言在同一个系统中的相互交互)。在处理dynamic类型的对象时,我们可以尝试访问该类型的任何成员,即使它不存在,并且在我们运行代码之前编译器也不会显示任何错误。

让我们创建一个包含一个成员的对象:

dynamic account = new
{
		Name = "Test"
};

之后,让我们声明一个新变量passage并将 account对象的Password值分配给它:

var password = account.Password;

到目前为止,代码不会引发任何异常,但是当我们运行应用程序时,我们会得到一个RuntimeBinderException。这是因为account对象没有名为Password的成员。

此外,我们可以为动态变量分配任何类型的值:

dynamic count = 1;
Assert.IsType<int>(count);

在此方法中,我们声明count为dynamic变量,并为其赋值1。然后,在运行时,count的类型将是 int.这意味着动态对象将采用分配给它们的值的类型。

动态变量在我们的应用程序中具有灵活性,因为编译器不会检查变量。但是,使用动态变量可能会导致我们的应用程序中出现错误。例如,如果我们拼错变量或尝试访问不存在的变量,应用程序会抛出一个RuntimeBinderException,因为在编译时没有静态检查。

什么是 ExpandoObject?

C# 中的ExpandoObject允许我们创建实例,并且在运行时动态添加或删除实例的变量。除了添加变量之外,还使我们能够设置和获取实例变量的值。

要创建ExpandoObject的实例,我们需要使用关键字dynamic。由于我们需要动态地将变量添加到 ExpandoObject,因此我们需要能够调用其中不存在的成员而不会出现编译错误,这就是 dynamic 关键字有用的地方。

让我们创建一个 ExpandoObject 的实例:

dynamic article = new ExpandoObject();
article.Author = "Laobai";
article.Year = 2023;
Assert.Equal("Laobai", article.Author);
Assert.Equal(2023, article.Year);

使用点号运算符(.),我们向对象article添加两个带有值的新属性。然后,我们只需再次使用点号运算符来访问这些值。

另外再让我们看看如何向 ExpandoObject 添加方法:

article.read = 1000;
article.Read = (Action)(() => { article.read++; });
article.Read();

我们首先添加值1000的属性read。然后,我们添加Read为委托函数,此方法仅进行read的递增。

调用此方法时,每次read的值都会增加1。

遍历ExpandoObject成员

ExpandoObject类实现了接口IDictionary<string, object>。这意味着每次我们向对象添加新成员时,它们都会存储为键值对。

为了获取ExpandoObject实例的所有值,我们遍历对象:

dynamic country = new ExpandoObject();
country.Name = "China";
country.Population = "1.4 Billion people";
foreach (KeyValuePair<string, object> keyValuePair in country)
{
		_testOutputHelper.WriteLine(#34;{keyValuePair.Key} : {keyValuePair.Value}");
}

我们使用一个循环,用于获取动态对象的值。然后,我们将结果打印到控制台。

当我们运行此方法时,我们得到:

Name : China
Population : 1.4 Billion people

现在我们已经学习了如何从 ExpandoObject 中添加和读取值,让我们看看如何从对象中删除属性。

从ExpandoObject实例中删除属性

让我们创建一个新的ExpandoObject实例并从中删除一个属性:

dynamic person = new ExpandoObject();
person.Age = 30;
person.Name = "Laobai";
((IDictionary<string, object>)person).Remove("Age");

我们首先创建一个对象并向其添加两个属性。之后,我们将对象强制转换为接口IDictionary<string, object>。然后,我们调用Remove方法。这将从person对象中删除Age属性。

对ExpandoObject属性更改的监听

ExpandoObject 类还实现了接口INotifyPropertyChanged,每次我们添加、删除或更新对象属性时,该接口都会触发一个事件。该事件会通知在PropertyChanged中的订阅者。

让我们试看看:

dynamic person = new ExpandoObject();
((INotifyPropertyChanged)person).PropertyChanged += (_, e) =>
{
		_testOutputHelper.WriteLine(#34;Property changed: {e.PropertyName}");
};
person.Name = "Laobai";

我们首先声明一个新的动态对象person。然后,我们通过PropertyChanged订阅了属性更改的事件。最后,我们向对象person添加一个新属性Name来触发事件。调用此方法,我们将得到:

Property changed: Name

什么是DynamicObject?

该类允许我们创建自定义动态对象。它帮助我们指定可以对动态对象执行的操作以及如何执行这些操作。

但是,我们只能在应用程序中继承该类,因为我们不能直接实例化它。继承类后,我们需要覆盖实现自定义逻辑所需的方法。

我们将在这里介绍两个主要方法:

  • TryGetMember()方法
  • TrySetMember()方法

TryGetMember()方法允许我们在运行时自定义动态访问成员值的行为。为了自定义行为,我们必须重写该方法

public override bool TryGetMember(GetMemberBinder binder, out object result)

参数GetMemberBinder提供有关正在访问其成员的对象的信息。result参数是获取操作的结果。

TrySetMember()方法允许我们自定义设置动态对象成员值的操作:

public override bool TrySetMember(SetMemberBinder binder, object value)

与此类似,该方法也采用两个参数。参数SetMemberBinder提供有关正在设置的成员的信息。参数value是成员将要设置的值。

如果操作成功,这两种方法都应返回true,否则,它们应返回 false。

使用DynamicObject类型

让我们创建一个继承DynamicObject的类Person:

public class Person : DynamicObject
{
    private readonly Dictionary<string, object?> _personalInformation;
    public Person()
    {
   		 _personalInformation = new Dictionary<string, object?>();
    }
}

该类有一个类型Dictionary<string, object?>的和一个构造函数字段。

现在让我们实现该类的两个方法:

public class Person : DynamicObject
{
    private readonly Dictionary<string, object?> _personalInformation;
    public Person()
    {
        _personalInformation = new Dictionary<string, object?>();
    }
    public override bool TryGetMember(GetMemberBinder binder, out object? result)
    {
        var key = binder.Name;
        return _personalInformation.TryGetValue(key, out result);
    }
    public override bool TrySetMember(SetMemberBinder binder, object? value)
    {
        var key = binder.Name;
        _personalInformation[key] = value;
        return true;
    }
}

首先,我们重写TryGetMember方法以从_personalInformation中获取属性的值。然后,TrySetMember方法帮助我们在_personalInformation上设置属性的值。

为了测试这些方法,我们可以将类Person实例化为dynamic:

dynamic person = new Person();
person.Name = "Laobai";
person.Age = 30;
person.Address = "si chou zhilu";

在本例中,我们将向动态对象添加三个新属性。

然后我们再向类添加一个新方法:

public void PrintInfo()
{
  Console.WriteLine("Personal Information:");
  foreach (var info in _personalInformation)
  {
  	Console.WriteLine(#34;{info.Key}: {info.Value}");
  }
}

调用此方法,我们得到:

Personal Information:
Name: Laobai
Age: 30
Address: si chou zhilu

PrintInfo方法从对象person动态读取值并将其打印到控制台。

这里只是展示了一个非常简化的用例。但是,这些继承的方法可以进一步被定制。一个比较好的场景就是从配置文件中读取值生成一个动态的配置对象。

在分别查看了动态类型之后,让我们继续查看它们之间的差异。

ExpandoObject、DynamicObject 和 Dynamic 之间的差异

ExpandoObject 类允许我们在运行时向动态对象实例添加成员并动态使用它们。在内部,它实现接口IDictionary<string, object>,使其能够在键值对中存储属性和值。

要从中添加或访问ExpandoObject的属性,我们可以使用点号运算符或将其视为字典。此外,我们不需要显式定义另一个类或重写成员即可在我们的应用程序中使用它。

DynamicObject是一个更高级的类,它允许我们自定义动态对象的行为。与类相比,该类更灵活、更强大,因为我们可以使用它来为动态对象的操作创建自定义逻辑。对于我们需要对创建的动态对象进行更多控制的情况,这是一个不错的选择。

而dynamic则是一种帮助我们创建动态类型对象的类型。当我们将一个变量声明为dynamic时,编译器不会检查变量的类型。考虑到这一点,我们可以为动态对象分配任何类型的值。我们还可以在没有编译时检查的情况下对对象执行操作。它也是在我们使用ExpandoObject和DynamicObject时应该使用的类型。

好了,希望通过此文,我们可以对这三种不同类型有所了解。

最后,Happy Coding Happy Life[憨笑]

相关推荐

Nginx 响应提速10倍,你需要知道的缓存性能优化——FastCGI调优
Nginx 响应提速10倍,你需要知道的缓存性能优化——FastCGI调优

Nginx缓存优化是帮助大家提升网站性能的重要操作之一,proxy_cache主要用于反向代理时,对后端内容源服务器进行缓存;fastcgi_cache主要用于...

2024-05-20 14:44 gowuye

王者荣耀天魔缭乱和逐梦之音返场活动地址 3月22日开启返场活动
王者荣耀天魔缭乱和逐梦之音返场活动地址 3月22日开启返场活动

王者荣耀官方终于确定了天魔缭乱和逐梦之音的返场活动,这让不少小伙伴乐开了花,返场活动将会在3月22日开启,下面就带来王者荣耀天魔缭乱和逐梦之音返场活动地址!王者...

2024-05-20 14:44 gowuye

常见的嵌入式web服务器有哪些?

嵌入式WEB服务器常见的有:Lighttpd,Shttpd,Thttpd,Boa,Mini_httpd,Appweb,Goahead。Lighttpd地址:http://www.light...

简述几款常见的嵌入式web服务器
简述几款常见的嵌入式web服务器

嵌入式web服务器,是web服务器当中的一种,是基于嵌入式系统而实现的web服务器。指的是在嵌入式系统(通俗点就是单片机系统)上实现的一个web服务器,可以通过...

2024-05-20 14:44 gowuye

教你如何利用fastcgi_cache缓存加速WordPress

在使用nginx缓存之前,必须在nginx里面加载专门的模块,这个模块叫做ngx_cache_purge。添加ngx_cache_purge模块下载ngx_cache_purge模块ngx_cache...

扫描WordPress漏洞

检测已知漏洞WPScan是一款广泛使用的WordPress安全扫描工具,它的一项重要功能是检测已知漏洞。在这篇文章中,我们将深入探讨WPScan如何检测已知漏洞,并结合实际示例,帮助读者更好地理解和应...

消灭 Bug!推荐几个给力的开源 Bug 跟踪工具
消灭 Bug!推荐几个给力的开源 Bug 跟踪工具

在这个充满bug的世界里,最遥远的距离不是生与死,而是你亲手制造的bug就在你眼前,你却怎么都找不到它。因此本文准备了7款优秀的开源bug跟踪系...

2024-05-20 14:43 gowuye

生物信息分析入门全攻略

生物信息学是生命科学研究的重大前沿领域,未来将占据生命科学研究的半壁江山。已经有越来越多的小伙伴投入到生物信息的学习中,但是入门难、深入慢、摸不到方向等都成为持续学习的拦路虎。本文根据生物信息技术大牛...

elkb实践经验,再赠送一套复杂的配置文件
elkb实践经验,再赠送一套复杂的配置文件

原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处。宝剑锋从磨砺出,梅花香自苦寒来。诗人白居易,三月下江南,看到沿路开放的桃花,心潮澎湃...

2024-05-20 14:43 gowuye

超详细从0到1 搭建ELK监控
超详细从0到1 搭建ELK监控

监控分类?Metrics用于记录可聚合的数据。例如,1、队列的当前深度可被定义为一个度量值,在元素入队或出队时被更新;HTTP请求个数可被定义为一个计数器,...

2024-05-20 14:42 gowuye

嵌入式开发 之Web配置页面开发
嵌入式开发 之Web配置页面开发

1.PHP是最好的语言??开发动态页面首选的语言是PHP,村村不能在这里忽悠人,如果你的硬件性能允许切略懂PHP,看到这里就可以退出了。本文面向的受众是Linu...

2024-05-20 14:42 gowuye

Python开发一个网站目录扫描工具用来检测网站是否有漏洞?
Python开发一个网站目录扫描工具用来检测网站是否有漏洞?

开发一个网站目录扫描工具是用来检测网站是否有非法目录请求的一个常见需求之一,我们要通过这个扫描工具来找到通过某个域名可以访问到的网站路径,可能对于有些系统来讲,...

2024-05-20 14:42 gowuye

创建一个类似Youtube的Id——使用PHP/Python/JS/Java/SQL

id通常都是用数字,不巧的是只有10个数字来使用,所以如果你有很多的记录,id往往变得非常冗长。当然对于计算机来说无所谓,但我们更希望id尽可能短。所以我们如何能使id变短?我们可以利用字母让它们附加...

快速云:有助于移动应用安全开发的五条妙计
快速云:有助于移动应用安全开发的五条妙计

许多企业不断地向其开发团队提供培训。但是某些漏洞,如早在十多年前就发现的SQL注入,如今仍广泛存在于各种应用中。因而,安全培训永不过时。在开发移动应用时,开发者...

2024-05-20 14:41 gowuye

洛杉矶国际电影节最佳动画短片奖影片《G’DAY》正式全网上映
洛杉矶国际电影节最佳动画短片奖影片《G’DAY》正式全网上映

7月2日,由M&CSaatchi创作,由深受好评的澳大利亚导演迈克尔·格雷西执导的动画短片《G’day》,正式在全网上映。该影片因其出色的创意赢得了洛...

2024-05-20 14:41 gowuye

取消回复欢迎 发表评论: