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中的某些列的数据是 ...
随机推荐
- elasticsearch中runtime_mapping实战
背景:需要根据一个实时计算处理的结果值进行排序,数据从es中查询.(基于业务背景:佣金排序) es版本:7.17.1:spring-data-elasticsearch版本:4.3.9 方式一:mys ...
- 【K8S】Docker向私有仓库拉取/推送镜像报错(http: server gave HTTP response to HTTPS client)
这里,我们搭建的Harbor仓库的地址为 http://192.168.175.101:1180. 报错信息如下所示. [root@binghe101 ~]# docker login 192.168 ...
- Java内存马1-传统web内存马
1.前置知识 (1)Tomcat Tomcat是一个开源的.轻量级的.用于Java Servlet和JavaServer Pages(JSP)的Web应用程序服务器.它是Apache软件基金会的一个项 ...
- Generalized Focal Loss:Focal loss魔改以及预测框概率分布,保涨点 | NeurIPS 2020
为了高效地学习准确的预测框及其分布,论文对Focal loss进行拓展,提出了能够优化连续值目标的Generalized Focal loss,包含Quality Focal loss和Distrib ...
- KingbaseES 查询优化消除SubPlan
说明: 日常业务系统在使用SQL语句进行查询时,开发人员容易将sql查询的子查询放到select语句中进行使用,会造成sql性能的下降. 数据准备: test=# test=# select coun ...
- Java 中的异常处理机制的简单原理和应用。
Java 中的异常处理机制的简单原理和应用. 异常是指 java 程序运行时(非编译)所发生的非正常情况或错误. Java 对异常进行了分类,不同类型的异常分别用不同的 Java 类表示,所有异常的根 ...
- 【已解决】Exception in thread "main" java.lang.RuntimeException: java.net.ConnectException
没有启动hadoop集群
- 8 JavaScript函数
8 JavaScript函数 在JS中声明函数和python差不多. 也要有一个关键字顶在前面. python是def, 到了JS里换成了function, 只不过在JS中没有像python那么死板, ...
- #差分约束,Floyd#洛谷 2474 [SCOI2008]天平
题目 分析 非传统差分约束?? 注意只有结果保证惟一的选法才统计在内 这就为差分约束提供了依据 以左边重为例,假设现在选择的砝码为\(i,j\), 那么\(\because A+B>i+j\th ...
- JDK11的新特性:新的HTTP API
目录 简介 使用HTTP Client请求的基本流程 创建HTTP Client 创建HTTP Request 发送HTTP请求 异步HTTP请求 总结 JDK11的新特性:新的HTTP API 简介 ...