dotnet 使用 FormatterServices 的 GetUninitializedObject 方法在丢失 DLL 情况下能否执行
在 dotnet 里面,可以使用 FormatterServices 的 GetUninitializedObject 方法可以实现只创建对象,而不调用对象的构造函数方法。而如果在使用此方法时,存在了 DLL 缺失的情况,此时能否让此方法运行通过,创建出空的对象
答案是可以创建成功,也可以创建不成功。当所有碰到的字段都是引用类型的时候,可以创建成功。如果存在值类型,但是值类型的 DLL 定义文件被删除,将会失败
下面来写一点测试的逻辑,如下面代码分别定义 F1 和 F2 和 F3 三个不同的类型
class F1
{
public F2 F2 { get; } = new F2();
}
class F2
{
public F3 F3 { get; } = new F3();
}
public class F3
{
}
在 Main 函数里面使用下面代码调用 FormatterServices 的 GetUninitializedObject 方法创建对象
class Program
{
static void Main(string[] args)
{
var f1 = FormatterServices.GetUninitializedObject(typeof(F1));
}
}
接着将 F3 类放在另一个项目里面,然后让此项目引用包含 F3 类的项目。在构建完成之后,删除包含 F3 类的项目的输出 DLL 文件。接着运行 Main 方法,可以看到实际上 f1 对象还是被创建才出来,不会炸掉
可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 2f00793486fcb1962de7e368ec527cf1169db135
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
获取代码之后,进入 JinaldalurhaBelnallbune 文件夹
其实此时即使获取 F2 的类型,通过反射拿到所有的成员,也是可以获取到的,如下图

可以看到原本是 F3 的类型对应的属性,在反射拿到的是 System.Reflection.RuntimePropertyInfo 类型

可以看到对应的模块被删除时,只会提示说文件找不到,而不会让反射失败
接下来试试使用结构体的方式,也就是字段实际是值类型的方式,修改 F2 和 F3 从引用类型修改为结构体,代码如下
struct F2
{
public F3 F3 { get; }
}
public struct F3
{
static F3()
{
}
}
依然将 F3 放在另一个程序集,然后在输出文件里面删除此程序集的 DLL 文件。尝试运行代码,可以看到此时运行将会失败

原因是因为值类型需要计算对象的占用的内存空间的大小,在准备创建 F1 的时候需要开始计算 F2 的占用空间,因为 F2 是一个结构体。但是 F2 里面引用了 F3 类型,此时 F2 就需要开始计算 F3 的空间,然而定义 F3 占用空间大小的数据放在了被删除的程序集里面,因此拿不到 F3 的占用空间大小,从而计算不出 F2 的空间大小,也就无法创建 F1 对象,因此失败
那为什么 F3 的占用空间大小需要放在定义 F3 的程序集里面,不能放在被引用的如 F2 所在的程序集里面?原因在于 dotnet 的应用可以支持 DLL 兼容更新,如我可以方便的更改 F3 类型的定义,如添加一个字段。那么此时 F3 的占用内存空间大小自然就需要修改了。然而此时我可以做到不更改 F2 所在的程序集,只需要更新 F3 所在的程序集即可,这就是因为在运行时里面读取了 F3 所在的程序集拿到了 F3 的占用内存空间的大小,不需要依赖在 F2 所在的程序集的定义
可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 415664a5516c778db662dd519e9114a320a4d690
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
获取代码之后,进入 JinaldalurhaBelnallbune 文件夹
如果不是直接的引用的类型找不到定义的程序集,那依然可以成功,将 F2 从结构体修改为引用类型,如下面代码
class F2
{
public F3 F3 { get; }
}
此时删除 F3 所在的程序集,依然可以创建出来 F1 对象
通过上文可以了解到 F1 对象的内存空间,可以计算出来,因为 F2 是引用类型,引用类型占用的字段内存空间是固定的。所以就不需要再去计算 F2 里面包含的 F3 结构体的占用空间
当然,依然让 F2 是结构体类型,但是将 F3 修改为引用类型,也能创建成功。原因是 F2 结构体在不知道 F3 的程序集时依然可以根据引用类型占用的字段空间是固定的,计算出包含 F3 的属性的字段占用的内存,因此不需要去读取 F3 所在的程序集
通过上文可以了解到 dotnet 里面加载程序集的机制
dotnet 使用 FormatterServices 的 GetUninitializedObject 方法在丢失 DLL 情况下能否执行的更多相关文章
- delphi中的ClientDataSet组件的open和Execute方法各自在什么情况下用?
ClientDataSet组件本来是给midas用的,也是所谓的borland的三层数据技术,使用这个控件必须发行midas.dll挺麻烦的 open是通过应用的SQL语句为SELECTexecute ...
- Linux在丢失的情况下重置密码
1.开机菜单是 移动光标到第一行 --敲击e 2.找到UTF-8,加上空格rd.break,敲击ctrl+x 3.输入以下命令 mount -o remount,rw /sysroot chroot ...
- DotNet生成随机数的一些方法
在项目开发中,一般都会使用到“随机数”,但是在DotNet中的随机数并非真正的随机数,可在一些情况下生成重复的数字,现在总结一下在项目中生成随机数的方法. 1.随机布尔值: /// <summa ...
- ASP.NET Session丢失的情况
正常操作情况下会有ASP.NET Session丢失的情况出现.因为程序是在不停的被操作,排除Session超时的可能.另外,Session超时时间被设定成60分钟,不会这么快就超时的. 现在我就把原 ...
- 在没备份undo的情况下,undo丢失,重启数据库报ORA-01157错误
今天做了一下undo隐藏参数的实验 在没有备份的情况下,删除正在使用的undo,然后关机 (本次使用的的oracle的隐藏参数,慎用!!!!!!!!!!!!!!) idle> select * ...
- 后端把Long类型的数据传给前端,前端可能会出现精度丢失的情况,以及解决方案
后端把Long类型的数据传给前端,前端可能会出现精度丢失的情况.例如:201511200001725439这样一个Long类型的整数,传给前端后会变成201511200001725440. 解决方法: ...
- RabbitMQ-如何保证消息在99.99%的情况下不丢失
1. 简介 MQ虽然帮我们解决了很多问题,但是也带来了很多问题,其中最麻烦的就是,如何保证消息的可靠性传输. 我们在聊如何保证消息的可靠性传输之前,先考虑下哪些情况下会出现消息丢失的情况. 首先,上图 ...
- 什么情况下才要重写Objective-C中的description方法
特别注意: 千万不要在description方法中同时使用%@和self,同时使用了%@和self,代表要调用self的description方法,因此最终会导致程序陷入死循环,循环调用descrip ...
- 如何让ASP.NET Web API的Action方法在希望的Culture下执行
在今天编辑推荐的<Hello Web API系列教程--Web API与国际化>一文中,作者通过自定义的HttpMessageHandler的方式根据请求的Accep-Language报头 ...
- 关于在gridview中有dorpdownlist的情况下使用自带编辑模板的方法
今天记录一下在gridview中,如果有dropdownlist的情况下使用gridview自带编辑模式的方法. 好吧,今天的这个问题有点绕,详细解释一下目的. 因为gridview中的某些列的数据是 ...
随机推荐
- 三维模型3DTile格式轻量化压缩处理效率提高的技术方浅析
三维模型3DTile格式轻量化压缩处理效率提高的技术方浅析 随着三维模型在各个领域的广泛应用,对于其格式的轻量化压缩处理和效率提高的需求也越发迫切.本文将介绍一些技术方法,帮助实现三维模型3DTile ...
- 工作记录:TypeScript从入门到项目实战(项目篇)
Vue项目中使用 前面两篇介绍过TypeScript基础和较深入的东西,本章介绍如何在Vue项目中使用. 项目创建 创建项目直接使用Vue-cli创建 下面是步骤: 1.运行vuecli, 2.选择合 ...
- 记录--Vue3 封装 ECharts 通用组件
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 按需导入的配置文件 配置文件这里就不再赘述,内容都是一样的,主打一个随用随取,按需导入. import * as echarts from ...
- management.endpoints.web.exposure.include
yml配置文件中 management: endpoints: web: exposure: include: '*' properties配置文件中 management.endpoints.web ...
- Linux实现远程登录基本操作
Linux配置远程登录 1.实验目的 通过配置redhat的静态IPV4,通过xshell登录,实现远程指令控制.在实践过程中,了解linux的基本结构和操作,能够初步地使用linux的常用软件.目的 ...
- STAR法则是什么(如何把一件事表达清楚)
STAR法则,即为Situation Task Action Result的缩写,具体含义是: Situation: 事情是在什么情况下发生 Task: 你是如何明确你的任务的 Action: 针对这 ...
- MySQL面试必备一之索引
本文首发于公众号:Hunter后端 原文链接:MySQL面试必备一之索引 在面试过程中,会有一些关于 MySQL 索引相关的问题,以下总结了一些: MySQL 的数据存储使用的是什么索引结构 B+ 树 ...
- GraphQl in ASP.NET Core
GraphQl in ASP.NET Core https://graphql.cn/ https://graphql-dotnet.github.io/docs/getting-started/ar ...
- 汇编语言-int指令
int 指令 int 指令的格式为:int n,n为中断类型码,它的功能是引发终端过程. CPU执行int n指令,相当于引发一个n号中断的中断过程,执行过程如下. 取中断类型码n: 标志寄存器入栈, ...
- Visual Studio 2022的安装 - 编程手把手系列文章
工欲善其事,必先利其器. 今天讲的是编程开发工具Visual Studio 2022的安装.作为手把手系列的开始,需要先对进行编程所使用的工具进行了解.此博文从下面几个步骤入手,对VS 2022这个开 ...