[C#学习笔记] - dynamic跨程序集无法获取匿名类属性的思考及解决方案

场景

有个需求,需要传动态参数,想到了匿名类。但在实际操作中,dynamic类型无法获取属性值。

// Assembly_A
public class Client
{
	public void OnMessage(dynamic msg)
	{
		Console.WriteLine(msg.Date);
	}
}

// Assembly_B
public class Server
{
	public void SendMessage(dynamic msg)
	{
		var c = new Client();
		c.OnMessage(new {Date = "20200828"})
	}
}

当运行至Console.WriteLine(msg.Date);时,抛出异常。
在这里插入图片描述
错误信息为:
“object”未包含Date的定义。
“Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: ‘object’ does not contain a definition for ‘Value’”

查了资料,原因是匿名类的属性访问权限是internal,只有在同一程序集(Assembly)中才能使用。一旦跨程序集使用,则会出现无法访问的错误。所以dynamic在跨程序集的使用场景中,受到很多的限制。(匿名方法可能也有这样的情况,未证实)。

但我发现,这里有个有意思的情况。虽然跨程序集无法直接调用属性,但是dynamic的数据确实传递过来了。如下图
在这里插入图片描述
这样就可以通过json的序列化及反序列化,重新生成一个dynamic类型。

解决方案

using Newtonsoft.Json;

// Assembly_A
public class Client
{
	public void OnMessage(dynamic msg)
	{
		// 收到dynamic的msg后,先序列化成json字符串,然后在将json字符串反序列化成dynamic类型。
		var json = JsonConvert.SerializeObject(msg, Formatting.Indented);
		var newMsg = JsonConvert.DeserializeObject<dynamic>(json);
		Console.WriteLine(newMsg.Date);
	}
}

// Assembly_B
public class Server
{
	public void SendMessage(dynamic msg)
	{
		var c = new Client();
		c.OnMessage(new {Date = "20200828"})
	}
}

需要注意的是,按这种方式反序列化得到的新的,所以数据类型丢失了,变成了object类型。需要类型转换。
其实,像这种传递变参的场景,使用Dictionary<string, Object>也可以满足。
《C#比较dynamic和Dictionary性能》这篇文章的性能测试,dynamic有基础消耗,次数越大,对比Dictionary形式性能更加占优。但考虑到我这里的场景是跨程序集,dynamic的使用没有那么流畅,且还多了json的序列化和反序列化的损耗,感觉得不偿失,最终还是用了Dictionary的方案。但话说回来,如果不跨程序集,那肯定用dynamic

《C# 4.0跨程序集使用"dynamic"》 https://www.cnblogs.com/Gildor/archive/2010/03/19/1689466.html
https://www.cnblogs.com/willingtolove/p/11204018.html
https://www.jianshu.com/p/1d74d6c86295

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MapObject(简称MO)是一种用于开发GIS应用程序的可视化编程组件,可以在VB、VC、Delphi、C#等开发环境中使用。其主要功能包括地图显示、地图浏览、地图查询、符号绘制、地图分析等。 MO的核心是Map对象,它代表了一张地图。Map对象包含了地图数据、地图的显示方式、地图的空间参考等信息。在MO中,地图数据通常以Shapefile格式存储,可以包括点、线、面等空间要素。 MO的编程模型是基于事件的,即程序通过响应组件的事件来完成操作。例如,当用户在地图上点击时,会触发Map控件的MouseDown事件,程序可以在该事件中编写代码来响应用户的操作。 MO的程序设计入门可以从以下几个方面来学习: 1. 创建地图控件:在VB、VC等开发环境中,可以通过向窗体添加Map控件来创建地图控件。在Delphi中,需要在窗体上添加一个TMapControl控件,再通过代码创建Map对象并将其与TMapControl关联起来。 2. 加载地图数据:可以使用Map对象的AddLayer方法,将Shapefile文件加载到地图中。加载后,可以设置要素的显示方式、标注等属性。 3. 地图操作:可以通过Map控件提供的方法,实现地图的缩放、平移、旋转等操作。例如,可以通过调用Map控件的ZoomIn方法实现地图放大,通过调用Map控件的Pan方法实现地图平移。 4. 地图查询:可以使用Map对象的SelectByShape方法,根据指定的查询条件进行地图查询。查询结果可以在地图上高亮显示。 5. 符号绘制:可以使用Map对象中的Symbol对象,绘制点、线、面等符号。例如,可以使用Symbol对象的DrawPoint方法,绘制一个点符号。 以上是MO的一些基础概念和编程入门,希望可以帮助你进行MO的学习和应用开发。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值