有时我期望只是创建出对象,但是不要调用对象的构造方法,可以通过使用 FormatterServices 的 GetUninitializedObject 函数来实现只创建对象不调用构造函数方法

这个 FormatterServices.GetUninitializedObject 方法大部分是用在做序列化使用的,然而在很多 IOC 容器,也都使用此方法来创建对象,而通过其他方法拿到构造函数

在 WPF 的 XAML 创建对象,也有用到此方法,详细请看 dotnet 读 WPF 源代码笔记 XAML 创建对象的方法

以下是一个实现的例子

            Foo foo = null;
try
{
foo = (Foo) FormatterServices.GetUninitializedObject(typeof(Foo));
var constructorInfo = typeof(Foo).GetConstructor(new Type[0]);
constructorInfo!.Invoke(foo, null);
}
catch
{
} class Foo
{ }

此方法可以用来处理在构造函数时,如果抛出了异常,但是此对象的 Dispose 需要被显式调用的问题。因为如果在构造函数抛出异常,那么在 C# 代码层面将拿不到此对象,也就无法调用对应的 Dispose 释放

如以下代码,可以看到 Foo 对象依然是空

        private void F1()
{
Foo foo = null;
try
{
foo = new Foo();
}
catch
{
// 忽略
}
} class Foo : IDisposable
{
public Foo()
{
throw new Exception("lindexi is doubi");
} ~Foo()
{
} public void Dispose()
{
GC.SuppressFinalize(this);
}
}

此时如果期望调用 Foo 对象的 Dispose 方法,将会因为拿不到对象而无法调用

解决此方法的做法就是通过只创建对象而不调用构造的方法,先拿到对象然后再调用构造,如果构造出错,依然还可以调用对象的 Dispose 方法

        private void F2()
{
Foo foo = null;
try
{
foo = (Foo) FormatterServices.GetUninitializedObject(typeof(Foo));
var constructorInfo = typeof(Foo).GetConstructor(new Type[0]);
constructorInfo!.Invoke(foo, null);
}
catch
{
// 忽略
}
finally
{
try
{
foo?.Dispose();
}
catch
{
// 可以调用到 Dispose 方法
}
}
} class Foo : IDisposable
{
public Foo()
{
throw new Exception("lindexi is doubi");
} ~Foo()
{
Dispose();
} public void Dispose()
{
GC.SuppressFinalize(this); throw new Exception($"lsj is doubi");
}
}

这个设计可以用来解决,如果对象的构造函数还没完全完成,调用释放函数将会抛出异常。如果没有使用如上方法,那么在释放函数的异常将会在 GC 回收线程抛出,而让应用程序退出

这就是为什么有很多容器和底层库喜欢使用此方法创建对象的原因

本文代码还请到 githubgitee 上阅读代码

可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 11077dd21a4ee5314757536ca379ecca6956b040

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git

获取代码之后,进入 HojeneceabuHallwhallhebo 文件夹

FormatterServices.GetUninitializedObject(Type) Method (System.Runtime.Serialization)

dotnet C# 只创建对象不调用构造函数方法的更多相关文章

  1. Python/dotNET Redis服务连接客户端调用SET方法的同时获取Redis服务器返回的内容

    在用Python或dotNET redis客户端连接redis服务器的时候,当你调用客户端的SET方法后同时还想得到其返回的字符串,那么需要处理一下. 1. Redis Python redis客户端 ...

  2. 通过工厂模式批量创建对象后调用其中方法 出现XXXis not a function()问题原因

    //通过工厂模式批量创建 function Computer(color,weight,logo){         var obj=new Object();         obj.color=c ...

  3. AjaxPro.dll,asp.net 前台js调用后台方法(无刷新)

    1.什么是Ajax Ajax是异步Javascript和XML(Asynchronous JavaScript and XML)的英文缩写."Ajax"这个名词的发明人是Jesse ...

  4. JS基础语法---创建对象---三种方式创建对象:调用系统的构造函数;自定义构造函数;字面量的方式

    创建对象三种方式: 调用系统的构造函数创建对象 自定义构造函数创建对象(结合第一种和需求通过工厂模式创建对象) 字面量的方式创建对象 第一种:调用系统的构造函数创建对象 //小苏举例子: //实例化对 ...

  5. [C#解惑] #1 在构造函数内调用虚方法

    谜题 在C#中,用virtual关键字修饰的方法(属性.事件)称为虚方法(属性.事件),表示该方法可以由派生类重写(override).虚方法是.NET中的重要概念,可以说在某种程度上,虚方法使得多态 ...

  6. C# 构造函数中调用虚方法的问题

    请看下面代码: using System; public class A{ public A(){ M1(); } public virtual void M1(){} } public class ...

  7. 避免在构造函数中调用虚方法(Do not call overridable methods in constructors)

    CLR中说道,不要在构造函数中调用虚方法,原因是假如被实例化的类型重写了虚方法,就会执行派生类型对虚方法的实现.但在这个时候,尚未完成对继承层次结构中所有字段的初始化.所以,调用虚方法会导致不可预测的 ...

  8. Java方法、构造方法的重载;创建对象;调用方法

    方法的重载 概念:多个同名但是不同参数的方法称为方法的重载 作用:编译器会根据调用时传递的实际参数自动判断具体调用的是哪个重载方法 特点:方法名相同:同一作用域:参数不同:数量不同 类型不同 顺序不同 ...

  9. 为什么字符串类型可以调用构造函数String的方法,却又不是它的实例

    从所周知,在js中定义一个字符串我们有两种办法: var a = new String("a"); var a = "a"; 第一种方法使用构造函数创建,作为S ...

  10. 反射-优化及程序集等(用委托的方式调用需要反射调用的方法(或者属性、字段),而不去使用Invoke方法)

    反射-优化及程序集等(用委托的方式调用需要反射调用的方法(或者属性.字段),而不去使用Invoke方法)   创建Delegate (1).Delegate.CreateDelegate(Type, ...

随机推荐

  1. 深度解读UUID:结构、原理以及生成机制

    What 是 UUID UUID (Universally Unique IDentifier) 通用唯一识别码 ,也称为 GUID (Globally Unique IDentifier) 全球唯一 ...

  2. 《Effective Java》笔记 4~5

    4. 类和接口 15. 使类和成员的可访问性最小化 把API与实现清晰地隔离开,组件间通过API进行通信,不需要知道其他模块的内部工作情况,这称为:实现信息隐藏或封装 解耦系统中的各个组件 尽可能地使 ...

  3. C#无需第三方插件实现json和table互转

    using System; using System.Collections.Generic; using System.Collections; using System.Linq; using S ...

  4. rabbitmq学习记录

    一.RabbitMQ的概念 RabbitMQ 是一个消息中间件:它接受并转发消息.你可以把它当做一个快递站点,当你要发送一个包裹时,你把你的包裹放到快递站,快递员最终会把你的快递送到收件人那里,按照这 ...

  5. Python爬虫爬取ECVA论文标题作者摘要关键字等信息并存储到mysql数据库

    网站截图: 源代码: 1 import re 2 import requests 3 import pymysql 4 from bs4 import BeautifulSoup 5 import l ...

  6. C++ future

    promise 空模板 非 void 特化,用于在线程间交流对象 void 特化,用于交流无状态事件 类模板 std::promise 提供存储值或异常的设施,之后通过 std::promise 对象 ...

  7. 测试开发之系统篇-Docker常用操作

    Docker容器(Container)的运行基于镜像(image),您可以在Docker Hub上检索,或通过Dockerfile文件自己构建镜像. 首先拉取MySQL官方镜像的最新版(latest) ...

  8. Impala 高性能、低延迟的大数据查询引擎

    Impala是什么? Impala提供对大数据更快速,交互式 SQL查询. Impala支持对存储在HDFS.HBase及S3等数据查询. Impala使用和Hive相同的元数据.SQL定义.ODBC ...

  9. chrome开发者工具

    官方文档 使用 DevTools 的工作区设置持久化 By Dave Gash Dave is a Tech Writer By Kayce Basques Technical Writer for ...

  10. #bitset优化,莫队#洛谷 5355 [Ynoi2017] 由乃的玉米田

    没有除法的版本 弱化版Blog 题目 分析 只针对除法而言,如果商很大直接用bitset判断是否存在, 否则直接预处理最近的答案判断是否在区间内即可,注意0要特判 代码 #include <cs ...