[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);时,抛出异常。
[C#学习笔记] - dynamic跨程序集无法获取匿名类属性的思考及解决方案_第1张图片
错误信息为:
“object”未包含Date的定义。
“Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: ‘object’ does not contain a definition for ‘Value’”

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

但我发现,这里有个有意思的情况。虽然跨程序集无法直接调用属性,但是dynamic的数据确实传递过来了。如下图
[C#学习笔记] - dynamic跨程序集无法获取匿名类属性的思考及解决方案_第2张图片
这样就可以通过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也可以满足。
按《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

你可能感兴趣的:(C#/.NET,CORE,学习笔记,错误处理,c#,json,dynamic,序列化反序列化)