Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >.NET Core/.NET 5.0 析构函数依然有效?

.NET Core/.NET 5.0 析构函数依然有效?

作者头像
huofo
发布于 2022-03-17 01:50:45
发布于 2022-03-17 01:50:45
33600
代码可运行
举报
文章被收录于专栏:huofo's bloghuofo's blog
运行总次数:0
代码可运行

前言

最近看到小伙伴在.NET Core中用到了析构函数,不禁打一疑问,大部分情况下,即使在.NET Framework中都不会怎么用到析构函数,我想在.NET Core中是否还依然有效呢?随着时间推移,迭代版本更新,有些当初我们脑海里认定的东西可能在当前并不再适用,这也就需要我们同步知识更新,如今我们所认为可能并不再是往昔我们所认为

.NET Core/.NET 5.0 析构函数

下面首先来看在.NET Framework中一个很标准的资源释放例子,这里我以4.7.2版本为例(其他版本一样)。创建基于当前应用程序域的指定程序集的指定实例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class CurrentDomainSandbox : IDisposable
{
    private AppDomain _domain = AppDomain.CreateDomain(
      "CurrentDomainSandbox",
      null,
      new AppDomainSetup
      {
        ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
        ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
      });

    ~CurrentDomainSandbox()
    {
      Dispose(false);
    }

    public T CreateInstance<T>(params object[] args)
      => (T)CreateInstance(typeof(T), args);

    private object CreateInstance(Type type, params object[] args)
    {
      HandleDisposed();

      return _domain.CreateInstanceAndUnwrap(
        type.Assembly.FullName,
        type.FullName,
        ignoreCase: false,
        bindingAttr: 0,
        binder: null,
        args: args,
        culture: null,
        activationAttributes: null);
    }

    public void Dispose()
    {
      Dispose(true);
      GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
      if (disposing && (_domain != null))
      {
        AppDomain.Unload(_domain);
        _domain = null;
      }
    }

    private void HandleDisposed()
    {
      if (_domain == null)
      {
        throw new ObjectDisposedException(null);
      }
    }
}

通过如上定义创建指定名称的应用程序域沙箱盒子,这样我们则可在此沙箱中创建对应程序集和实例,如此则可以其他域完全隔离且独立,然后在控制台进行如下调用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  var sanBox = new CurrentDomainSandbox();
  var instance = sanBox.CreateInstance<Program>();

还未完毕,直接运行将抛出如下异常

若用于远程传输,我们直接将主类继承自MarshalByRefObject就好,否则将此类通过Serializable特性标记,至于二者区别不详细展开。通过上述比较标准的例子我们则可以创建和释放未被使用的对应实例,我们看到用到了析构函数,但是我们发现最终调用Dispose方法,并未做任何处理,其实不然,问题出在对析构函数概念的理解

析构函数:在应用程序终止之前,将调用尚未被垃圾回收的所有对象的析构函数。析构函数本质是终结器,如果对象已被释放,在合适时机将自动调用Finalize方法,除非我们手动通过GC来抑制调用终结器(GC.SuppressFinalize),但不建议手动调用Finalize方法

通过资源释放标准例子,想必我们已经知道了析构函数的基本原理,接下来我们还是基于上述.NET Framework 4.7.2版本来演示析构函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ExampleDestructor
{
    public ExampleDestructor()
    {
      Console.WriteLine("初始化对象");
    }

    public void InvokeExampleMethod()
    {

    }

    ~ExampleDestructor()
    {
      Console.WriteLine("终结对象");
    }
}

既然析构函数是在应用程序终止前进行调用,那么我们在调用上述示例中方法时,如下调用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var exampleDestructor = new ExampleDestructor();

exampleDestructor.InvokeExampleMethod();

在.NET Framework中如我们所期望,在应用程序卸载时,此时会调用析构函数并进行相关打印。接下来到.NET Core,此时将断点放在析构函数中,将不会再调用,打印如下:

好了,以上只是我个人猜测,接下来我们直接看官方文档进行论证,官网对于析构函数链接

析构函数规范 https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/destructors

在.NET Framework应用程序中会尽一切合理努力在程序退出时调用析构函数进行清理(调用终结器方法),除非进行手动抑制,但在.NET Core并不能完全保证此行为。通过调用Collect来强制进行垃圾回收,但是在大多数情况下,应避免此调用,因为这可能会导致性能问题。为何出现如此差异呢?更详细分析请参看链接:

.NET Core析构函数理解分析 https://github.com/dotnet/runtime/issues/16028

根据此链接表述,可以这样理解:在.NET Core中不会在应用程序终止时运行终结器(针对可到达或不可到达的对象),根据建议,并不能保证所有可终结对象在关闭之前都将被终结。由于上述链接原因存在,所以在ECMA的C#5.0规范削弱了这一要求,因此.Net Core并不会违反此版本规范

总结

在应用程序关闭前,.NET Framework会尽一切合理努力调用析构函数即终结器进行资源清理,但在.NET Core中并不能保证此行为,所以在ECMA 语言规范中削弱了这一要求

基于上述,在.NET Core中使用析构函数并没有实质性意义

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-12-06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
什么叫应用程序域?(zhuan)
“域”,就是范围,环境,边界的意思,那么什么是应用程序域,官方给出的是这样的解释:操作系统和运行库环境通常会
全栈程序员站长
2022/09/07
3990
C# 的构造函数和析构函数
在C#编程中,构造函数和析构函数是控制对象生命周期的关键工具。构造函数用于初始化新创建的对象,而析构函数则在对象的生命周期结束时执行清理工作。正确地使用这两个特殊的方法可以提高代码的效率和可靠性。本文将深入探讨C#中的构造函数和析构函数,包括它们的基本概念、实现方式、高级用法和最佳实践。
Michel_Rolle
2024/10/08
2.6K0
C#:单例,闭包,委托与事件,线程,Parallel,Params,扩展方法,接口与抽象类
在对泛型的约束中,最常使用的关键字有where 和 new。 其中where关键字是约束所使用的泛型,该泛型必须是where后面的类,或者继承自该类。 new()说明所使用的泛型,必须具有无参构造函数,这是为了能够正确的初始化对象
立羽
2024/01/15
3550
C#-垃圾回收机制(GC)
The garbage collector is a common language runtime component that controls the allocation and release of managed memory。
郑子铭
2023/08/29
2.2K0
C#-垃圾回收机制(GC)
熟悉而陌生的新朋友——IAsyncDisposable
在.NET Core 3.0的版本更新中,官方我们带来了一个新的接口 IAsyncDisposable。
句幽
2021/09/08
7780
框架设计原则和规范(完)
祝大家圣诞节快乐!有事没事别出门,外面太!挤!了! 此文是《.NET:框架设计原则、规范》的读书笔记,本文内容较多,共分九章,今天推送最后一章。 1. 什么是好的框架 2. 框架设计原则 3. 命名规范 4. 类型设计规范 5. 成员设计规范 6. 扩展性设计 7. 异常 8. 使用规范 9. 设计模式 一、设计模式 1. 聚合组件 Aggregate Component: 把多个底层类型集中到一个高层类型中,以此来支持常用场景。例如E-mail组件、System.Net.WebClient、System.
韩伟
2018/03/05
1K0
C# IDispose
在C#中,IDisposable 是一个接口,用来提供一种机制来释放未使用的资源。当对象持有非托管资源(例如文件句柄、数据库连接、网络套接字等)时,需要实现 IDisposable 接口。
JusterZhu
2023/10/24
2320
C# IDispose
从C#垃圾回收(GC)机制中挖掘性能优化方案
GC,Garbage Collect,中文意思就是垃圾回收,指的是系统中的内存的分配和回收管理。其对系统性能的影响是不可小觑的。今天就来说一下关于GC优化的东西,这里并不着重说概念和理论,主要说一些实用的东西。关于概念和理论这里只做简单说明,具体的大家可以看微软官方文档。
跟着阿笨一起玩NET
2018/09/20
1.9K0
从C#垃圾回收(GC)机制中挖掘性能优化方案
编程小知识之 Dispose 模式
之前对 C# 中的 Dispose 模式只有些模糊印象,近来又了解了一些相关知识,在此简单做些记录~
用户2615200
2019/02/22
1.1K0
C#/.NET 中推荐的 Dispose 模式的实现
发布于 2015-02-05 02:10 更新于 2018-06-13 03:02
walterlv
2018/09/18
5700
关于构造函数与析构函数的分享
创建复杂的类类型的对象时,可能需要对一些数据或者对象中需要使用的资源进行一些初始化操作,比如设置成员的默认值,打开数据库,打开文件,等等,而这些准备工作,就可以放在类的构造函数中进行。
用户7053485
2020/03/12
1.4K0
.Net Remoting(基本操作) - Part.2
接下来我们考虑通常的情况,也就是 客户程序 与 宿主程序 位于不同的进程中的情况。
张子阳
2018/09/30
5870
.Net Remoting(基本操作) - Part.2
关于CLR内存管理一些深层次的讨论[上篇]
半年之前,PM让我在部门内部进行一次关于“内存泄露”的专题分享,我为此准备了一份PPT。今天无意中将其翻出来,觉得里面提到的关于CLR下关于内存管理部分的内存还有点意思。为此,今天按照PPT的内容写了一篇文章。本篇文章不会在讨论那些我们熟悉的话题,比如“值类型引用类型具有怎样的区别?”、“垃圾回收分为几个步骤?”、“Finalizer和Dispose有何不同”、等等,而是讨论一些不同的内容。整篇文章分上下两篇,上篇主要谈论的是“程序集(Assembly)和应用程序域(AppDomain)”。也许有的地方说的
蒋金楠
2018/02/08
6990
关于CLR内存管理一些深层次的讨论[上篇]
使用 .NET Core 3.0 的 AssemblyLoadContext 实现插件热加载
因为 .NET Core 不像 .NET Framework 一样支持动态创建与卸载 AppDomain,所以一直都没有好的方法实现插件热加载,好消息是,.NET Core 从 3.0 开始支持了可回收程序集 (Collectible Assembly),我们可以创建一个可回收的 AssemblyLoadContext,用它来加载与卸载程序集。关于 AssemblyLoadContext 的介绍与实现原理可以参考 yoyofx 的文章 与 我的文章。
梁规晓
2019/10/14
4.9K0
.Net Remoting(应用程序域) - Part.1
在互联网日渐普及,网络传输速度不断提高的情况下,分布式的应用程序是软件开发的一个重要方向。在.Net中,我们可以通过Web Service 或者Remoting 技术构建分布式应用程序(除此还有新一代的WCF,Windows Communication Foundation)。本文将简单介绍Remoting的一些基本概念,包括 应用程序域、Remoting构架、传值封送(Marshal by value)、传引用封送(Marshal by reference)、远程方法回调(Callback)、分别在Windows Service和IIS中寄宿宿主程序,最后我们介绍一下远程对象的生存期管理。
张子阳
2018/09/29
7010
.Net Remoting(应用程序域) - Part.1
解析.NET对象的跨应用程序域访问(上篇)
彭泽0902
2018/01/04
1.1K0
解析.NET对象的跨应用程序域访问(上篇)
C#小技巧|Dispose接口的正确使用方法
当前类中出现 IO 操作。或者其他 跨语言调用,窗口和网络连接 之的非托管资源调用,这时才需要自己是实现一个IDispose 接口。其他的时候你并不需要去实现这样一个接口。我的做法是一般的类继承一个 IReset 接口,这个接口内只包含一个 Reset 函数 . Dispose 接口是一个显示的调用,如果我们没有写这个接口,运行时他会在执行析构函数的时候清理资源。
keyle
2024/11/01
1820
C#小技巧|Dispose接口的正确使用方法
.net core 插件式开发
思考一种情况,短信发送,默认实现中只写了一种实现,因为某些原因该模块的所依赖的第三方无法继续提供服务,或者对于winform程序,某按钮单击,需要在运行时增加额外的操作,或者替换目前使用的功能,对于类似这样的需求,可以考虑使用插件式的方式搭建框架,以实现更灵活的可拆卸动态增加功能。 .net core 中提供了一种热加载外部dll的方式,可以满足该类型的需求 AssemblyLoadContext
FreeTimeWorker
2020/12/11
1.3K0
.net core 插件式开发
【A】兼容Core3.0后 Natasha 的隔离域与热编译操作。
深度克隆:https://github.com/night-moon-studio/DeepClone
心莱科技雪雁
2019/09/10
7110
【A】兼容Core3.0后 Natasha 的隔离域与热编译操作。
析构函数(C#)
 析构函数又称终结器,用于析构类的实例。 定义   析构函数(destructor) 与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete会自动调用析构函数后释放内存)。 析构函数简介 以C++语言为例:[1]  析构函数名也应与类名相同,只是在函数名前面加一个位取反符~,例如~stud( ),以区别于构造函数。它不能带任何参数,也没有返回值(包括void类型)。只能有一
房上的猫
2018/03/14
1.8K0
相关推荐
什么叫应用程序域?(zhuan)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验