当前位置: 首页 > news >正文

C# 子类强制转换为父类异常,引出的C#Dll加载机制,以及同类名同命名空间同dll程序集在C#中是否为同一个类的研究。

CSDN私自将文章改成了VIP文章,所以在这里也发一遍。

已知,子类B继承自父类A,但是在代码运行时,B类强制转换为A类,却报代码转换异常。
很奇怪的问题吧,不过这个也是难得机会,去研究C#运行的底层原理。

下面是报错的代码片段。

string className = _shapeReflectMap[typeName].ClassName;
Assembly assem = _shapeReflectMap[typeName].Assem;
Object obj = assem.CreateInstance(className); // 在dll程序集中 通过className实例化获取子类
Type type1 = obj.GetType().BaseType; // 获取父类类型
Type type2 = typeof(Shape);
Assembly assembly1 = type1.Assembly;
Assembly assembly2 = type2.Assembly;
string codeBase1 = assembly1.CodeBase;
string codeBase2 = assembly2.CodeBase;
try
{shape = (Shape)obj;
}
catch (Exception e)
{throw new Exception("反射创建Shape失败"+ "\n类型直接比较: " + (type1 == type2)+ "\n程序集直接比较: " + (assembly1 == assembly2)+ "\n类型全名比较: " + (type1.FullName == type2.FullName) + ": " + type1.FullName + " " + type2.FullName+ "\n程序集全名比较: " + (assembly1.FullName == assembly2.FullName) + ": " + assembly1.FullName + " " + assembly2.FullName+ "\ncodeBase1: " + codeBase1+ "\ncodeBase2: " + codeBase2+ "\n程序集路径比较: " + (codeBase1 == codeBase2)+ "\ncodeBase1.hash: " + codeBase1.GetHashCode()+ "\ncodeBase2.hash: " + codeBase2.GetHashCode()+ "\n", e);
}

下面是报错结果(其中的敏感字符串被替换成了xxx):

System.Exception: 反射创建Shape失败
类型直接比较: False
程序集直接比较: False
类型全名比较: True: xxx.WpfPlugin.Shape xxx.WpfPlugin.Shape
程序集全名比较: True: xxx.WpfPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null xxx.WpfPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
codeBase1: file:///D:/project/XXX/xxx.xxxClient.UI/xxx.xxxClient.UI/bin/Debug/Plugins/xxx.WpfPlugin.dll
codeBase2: file:///D:/project/XXX/xxx.xxxClient.UI/xxx.xxxClient.UI/bin/Debug/Plugins/xxx.WpfPlugin.dll
程序集路径比较: True
codeBase1.hash: -336973287
codeBase2.hash: -336973287---> System.InvalidCastException: 无法将类型为“xxx.WpfPlugin.Shapes.ImageButton”的对象强制转换为类型“xxx.WpfPlugin.Shape”。在 xxx.WpfPlugin.ctlUI.LoadXml(String xmlPath) 位置 D:\project\XXX\dll\PluginsSources\xxx.WpfPlugin\ctlUI.cs:行号 107--- 内部异常堆栈跟踪的结尾 ---在 xxx.WpfPlugin.ctlUI.LoadXml(String xmlPath) 位置 D:\project\XXX\dll\PluginsSources\xxx.WpfPlugin\ctlUI.cs:行号 111在 xxx.WpfPlugin.ctlUI.DisplayInit() 位置 D:\project\XXX\dll\PluginsSources\xxx.WpfPlugin\ctlUI.cs:行号 177

通过上面的代码可以看出,从子类中获取的父类type,和父类直接获取的type是完全一样的,命名空间,类名称,程序集和对应的dll文件,均相同。但是通过==判断,其在内存中并非同一个对象。

经过排查,发现代码中对该dll加载了两次,获得了两个程序集,而子类和父类分别来自不同的程序集,导致了无法进行类型转换。在修复该dll加载逻辑后问题便得到了解决。

可以推测出,C#判断两个类是否完全相同,除了看命名空间和类名以外,主要是判断两个类是否在同一个程序集实体中(内存中的同一个实体)。若一个dll加载了两遍,获得两个程序集对象,虽然两个程序集中的类完全相同,但是依然无法相互转换。

所以程序集最好有一个公共的存放处,统一的加载逻辑,不要养成需要某个类时直接去加载一遍dll的坏习惯。
也可以通过Assembly.GetExecutingAssembly()直接获取当前代码所在的程序集,避免重复加载。

http://www.jsqmd.com/news/358215/

相关文章:

  • 2026别错过!降AI率工具 千笔·降AIGC助手 VS 灵感风暴AI,专科生专属高效选择
  • 分享2026年值得推荐的管道自动焊机制造商 - mypinpai
  • 2026年管道自动焊机厂家排名,管道自动焊机价格多少钱 - mypinpai
  • leetcode 困难题 928. Minimize Malware Spread II 尽量减少恶意软件的传播 II
  • 实用指南:web服务及协议
  • 总结奕思瑞产品功能是否齐全,湖南地区购买指南 - 工业推荐榜
  • 分析催化燃烧实力厂商,盈和环保的服务与价格怎么样 - 工业推荐榜
  • 高质量家装电线产品怎么选购,重庆昂翡线缆值得考虑 - 工业品牌热点
  • 如何设置自定义Highcharts导出服务器?
  • 2026年流延机品牌制造商排行榜,性价比高的专业流延机厂家盘点 - 工业品牌热点
  • 2026年南京婚礼公司性价比排名,诺丁山花园厅及音响音乐表现如何 - 工业设备
  • 2026年亚崴龙门供应商十大排名,看看有哪些 - myqiye
  • 2026年压痕条品牌商推荐,启鑫科技定制生产服务超贴心 - 工业设备
  • 聊聊2026年靠谱的电焊条水玻璃厂家,哪家口碑好 - 工业品网
  • 在线少儿编程平台选购指南:根据学习目标选择高性价比编程课程 - 品牌测评鉴赏家
  • 分析北京易企宣智能营销顾问服务,费用多少钱合理? - 工业品网
  • 揭秘江苏盈和环保节能设备有限公司的费用情况,市场排名怎么样? - 工业推荐榜
  • 分享FRP采光瓦加工厂哪个值得选,质量有保障 - 工业品牌热点
  • 无人机续航模块技术分析
  • 2026年广东性价比高的照片回执服务排名,身份证驾驶员回执办理推荐 - myqiye
  • 2026赣州求推荐装修专业公司,如何选择合适的 - 工业品网
  • 与AI聊天机器人沟通的最佳方式:使用正式语言
  • 2026年口碑好的焰光秀厂家推荐,湖南浏阳源头焰光秀厂家全解析 - 工业设备
  • C#的MVVM架构中的几种数据绑定方式
  • 少儿编程体验课推荐:如何根据学习目标选购最适合的课程 - 品牌测评鉴赏家
  • 探究分布式电源接入对电网的影响:基于MATLAB的分析
  • AI元人文:多元共生与价值原语 ——智能时代文明操作系统的哲学构想
  • 建议收藏|倾心之选的AI论文工具 —— 千笔·专业学术智能体
  • python新能源汽车数据分析大屏可视化系统(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码
  • 2026年重庆白癜风医院推荐厂家推荐:重庆皮肤病医院哪家好、重庆皮肤病医院在哪里、重庆皮肤病医院官网选择指南 - 优质品牌商家