1 背景动机

关于模块或者程序集初始化工作一直是C#的一个痛点,微软内部外部都有大量的报告反应很多客户一直被这个问题困扰,这还不算没有统计上的客户。那么解决这个问题,还有基于什么样的考虑呢?

  • 在库加载的时候,能以最小的开销、无需用户显式调用任何接口,使客户做一些期望的和一次性的初始化。

  • 当前静态构造函数方法的一个最大的问题是运行时会对带有静态构造函数的类型做一些额外的检查。这是因为要决定静态构造函数是否需要被运行所必须的一步,但是这个又有着显著的开销影响。

  • 使源代码生成器在不需要用户显式调用一些东西的情况下能运行一些全局的初始化逻辑。

2 详细设计

C# 9.0将模块初始化器设计为一个Attribute,用这个Attribute来修饰进行模块初始化逻辑的方法,就实现了模块初始化功能。这个Attribute被命名为ModuleInitializerAttribute,具体定义如下:

using System;
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public sealed class ModuleInitializerAttribute : Attribute { }
}

如果要使用模块初始化器,你只要将ModuleInitializerAttribute用在符合下面要求的方法上就可以了。

  1. 该方法必须使静态的、无参的、返回值为void的函数。

  2. 该方法不能是泛型或者包含在泛型类型里

  3. 该方法必须是可从其所在模块里访问的。也就是说,方法的有效访问符必须是internal或者public,不能是局部方法。

using System.Runtime.CompilerServices;
class MyClass
{
[ModuleInitializer]
internal static void Initializer()
{
// ...
}
}

被修饰为ModuleInitializerAttribute的静态方法会被编译器在编译时,在全局的静态构造函数中生成此代码调用。如果有多个被修饰为初始化器的函数,则每个函数生成一个初始化器代码调用,这些初始化器代码调用代码会按照一定的顺序(类型名称顺序和代码顺序)生成。当模块在被加载时,全局静态构造函数开始执行,从而完成模块代码初始化工作。

3 问题与最佳实践

模块初始化器与静态构造函数之间有着一定的关联影响。因为模块初始化器是一个静态方法,因而其被调用执行前,必然会引起其所处类型的静态构造函数的执行。请参考下列示例:

static class ModuleInit
{
static ModuleInit()
{
//先执行
Console.WriteLine("ModuleInit静态构造函数 cctor");
} [ModuleInitializer]
internal static void Initializer()
{
//在静态构造函数执行后才执行
Console.WriteLine("模块初始化器");
}
}

在一个模块中指定多个模块初始化器的时候,他们之间的顺序也是一个值得注意的问题。以上这些问题的存在,就要求我们注意以下几点:

  • 在指定了模块初始化器的类型中,不要在静态构造函数中,写与模块初始化器中代码有着顺序依赖代码,最好的就是不要使用静态构造函数。

  • 多个模块初始化器之间的代码,也不要有任何依赖关系,保持各个初始化器代码的独立性。

4 结束语]

日常开发中,我们通常需要在模块初始化的时候,做一些前置性的准备工作,以前常采用静态构造函数这种不具有全局性方法,局限性很大,现在,这些都得到了完美解决。

如对您有价值,请推荐,您的鼓励是我继续的动力,在此万分感谢。关注本人公众号“码客风云”,享第一时间阅读最新文章。

C# 9.0新特性详解系列之三:模块初始化器的更多相关文章

  1. C# 9.0新特性详解系列之五:记录(record)和with表达式

    1 背景与动机 传统面向对象编程的核心思想是一个对象有着唯一标识,表现为对象引用,封装着随时可变的属性状态,如果你改变了一个属性的状态,这个对象还是原来那个对象,就是对象引用没有因为状态的改变而改变, ...

  2. C#9.0新特性详解系列之六:增强的模式匹配

    自C#7.0以来,模式匹配就作为C#的一项重要的新特性在不断地演化,这个借鉴于其小弟F#的函数式编程的概念,使得C#的本领越来越多,C#9.0就对模式匹配这一功能做了进一步的增强. 为了更为深入和全面 ...

  3. C# 9.0新特性详解系列之一:只初始化设置器(init only setter)

    1.背景与动机 自C#1.0版本以来,我们要定义一个不可变数据类型的基本做法就是:先声明字段为readonly,再声明只包含get访问器的属性.例子如下: struct Point { public ...

  4. C# 9.0新特性详解系列之二:扩展方法GetEnumerator支持foreach循环

    1.介绍 我们知道,我们要使一个类型支持foreach循环,就需要这个类型满足下面条件之一: 该类型实例如果实现了下列接口中的其中之一: System.Collections.IEnumerable ...

  5. [转]Servlet 3.0 新特性详解

    原文地址:http://blog.csdn.net/xiazdong/article/details/7208316 Servlet 3.0 新特性概览 1.Servlet.Filter.Listen ...

  6. Servlet 3.0 新特性详解

    转自:http://www.ibm.com/developerworks/cn/java/j-lo-servlet30/#major3 Servlet 是 Java EE 规范体系的重要组成部分,也是 ...

  7. 【转帖】Servlet 3.0 新特性详解

    http://www.ibm.com/developerworks/cn/java/j-lo-servlet30/ Servlet 3.0 新特性概述 Servlet 3.0 作为 Java EE 6 ...

  8. Servlet 3.0 新特性详解 (转载)

    原文地址:https://www.ibm.com/developerworks/cn/java/j-lo-servlet30/ Servlet 3.0 新特性概述 Servlet 3.0 作为 Jav ...

  9. Android6.0 新特性详解

    一 运行时权限 Android6.0 引入了一个新的应用权限模型,期望对用户更容易理解,更易用和更安全.该模型将标记为危险的权限从安装时权限(Install Time Permission)模型 移动 ...

随机推荐

  1. Shell脚本实现---Swarm集群部署实例(Swarm Cluster)

    Shell脚本实现---Swarm集群部署实例(Swarm Cluster) 一.机器环境(均是centos7.8) IP hostname 角色 192.168.10.200 manager-swa ...

  2. 循序渐进VUE+Element 前端应用开发(25)--- 各种界面组件的使用(1)

    在我们使用Vue+Element开发前端的时候,往往涉及到很多界面组件的使用,其中很多直接采用Element官方的案例即可,有些则是在这个基础上封装更好利用.更少代码的组件:另外有些则是直接采用第三方 ...

  3. kubernetes 基础知识

    1. kubernetes 包含几个组件 Kubernetes是什么:针对容器编排的一种分布式架构,是自动化容器操作的开源平台. 服务发现.内建负载均衡.强大的故障发现和自我修复机制.服务滚动升级和在 ...

  4. [Luogu P2341] [HAOI2006]受欢迎的牛 (缩点+bitset)

    题面 传送门:https://www.luogu.org/problemnew/show/P2341 Solution 前排提示,本蒟蒻做法既奇葩又麻烦 我们先可以把题目转换一下. 可以把一头牛喜欢另 ...

  5. Linux 环境下 C++ 的开发编译

    Linux环境下C++程序的开发编译学习笔记 环境:vmware 运行下的Ubuntu 16.04 姓名:谢津 时间:2018/5/24 内容:1)vim的安装及配置:2)第一个C++程序的编写与编译 ...

  6. ACM已刷题

    ZOJ: 1001.1002.1003.1004.1005.1006.1037.1045.1048.1049.1067.1087.1091.1016. swjtuoj: 2433 注:没链接的应该是最 ...

  7. display:none;visibility:hidden;opacity:0;之间的区别

    什么是回流 当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建.这就称为回流(reflow).每个页面至少需要一次回流,就是在页面第一次加载的时候,这时候是 ...

  8. JS基础算法题(二)

    1.1 数组去重的五种方法 数组去重:将数组中重复的元素去掉 JS数组没有删除具体元素的删除(只能删掉值,删不掉元素的索引),可以使用另外一个结构来进行存储 新数组 新对象 JS数组虽然本质可以删除第 ...

  9. Tim Urban:如何选择真正适合你的职业?

    Wait But Why是一个专注于写长博客的网站,Tim Urban是网站的创始人之一.Tim Urban专注于写长论文,与时下的轻度阅读完全背道而驰,文章动辄几千甚至上万字,但令人吃惊的是却拥有惊 ...

  10. EF Core 一、重识 EF

    重识EF EF Core 学习资料:https://docs.microsoft.com/zh-cn/ef/core/dbcontext-configuration/ 本为作为EF Core学习的开始 ...