深入探讨C#中的const、readonly关键字
作者:junjie 发布时间:2023-01-20 23:42:25
首先不可否认,这些在面试上会经常被面试官问起,但是你回答的让面试官满意吗?当然如果你知道了这些原理,或许你就不
怕了。既然说到了原理,我们还是从MSDN说起。
一:值得推敲的几个地方
1.先来看看msdn上面对const是怎么说的,我们会看到。不能修改,编译时常量这些关键性信息。
Q: const为什么不能被修改。
A:这个很简单,很多教科书上面都说,当编译器编译时,会将常量的值保存在该程序集的元数据中,下面我们做个实例
看一看。
①:新建一个projectA。
// ProjectA
public class TestClass
{
public const int CTRIP = int.MaxValue;
}
再建一个MainProject,引用下projectA。
using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine(TestClass.CTRIP);
Console.Read();
}
}
然后我们把mainproject运行起来。
既然我把mainproject跑起来了,并且也引用了Test.dll,刚才也说了,编译的时候会把常量值保存在程序集的元数据中,那我们
就找一找,打开ILdasm.exe,并且Ctrl+M。
很可惜,我并没有找到Ctrip的符号,也没有找到int.MaxValue,也没有找到所谓的0x7fffffff,倒是找到了一个Assembly的一些版本信息的元数据,那么这时候你可能会疑惑了,究竟const的值有没有保存到Assembly里面去呢?很简单的一个验证方法就是,把Mainproject下面bin中的Test.dll删除掉,看看会有怎么样的奇迹发生。
②: 聪明的你应该想到了,既然运行Demo.exe的时候不再加载Test.dll,而是直接从Demo的Assembly里面获取const值,
那是不是会有断层的事情发生,也就是版本不一致的情况,比如我已经修改了const值,然后把编译好的dll拷贝到Mainproject的bin目录下,直接运行Demo.exe,会不会出现MainProject读不到修改后的const值呢?这里我将const改成 int.MinValue。
下面我们可以试试看。
// ProjectA
public class TestClass
{
public const int CTRIP = int.MinValue;
}
好了,看到上面的结果,就进一步佐证了刚才的说法,const确确实实是保存在Assembly的元数据中,这里还要顺便提示一下,Enum本质上是const,所以它也存在我刚才说的断层的问题,说到这里,我想你对const的原理应该比较熟悉了,现在我们来看看Question的问题。既然是元数据,那什么是元数据?“描述数据的数据” 叫做元数据,既然它是基础的描述性数据,那么在定义好后是决对不能改变的,这个定义时也就是msdn说的编译时,是不是so easy呢?
Q: const为什么要做成静态的,而不是做成实例的
A: 其实通过对第一个Question的分析,很多东西我们应该都会豁然开朗,因为存在断层的问题,那么最好的方法就是const的值
永远也不要变,这样就可以避免问题的发生,既然是永远都不变的东西,当然是跟着“类型”走比跟着“实例”走要好的多,你说对不对,因为static是个小缓存,没必要new一下才产生。。。
Q: readonly字段只能在ctor中初始化吗?
A:这个问题蛮有意思的,我们知道readonly的意思就是只读字段的意思,我们知道一般的字段具有可读写的功能,
先还是看看编译器怎么说。
从编译器上可以看到,确实readonly的初始化还可以在“变量初始化”的时候进行初始化,那么这样说Question的答案应该就是否定的,但是真的是如此吗?我们都知道有一个东西叫做“语法糖”,而且经常是编译器提供给我们用的,所以真正的想看到发生了什么,只能用ILDasm.exe 穿透编译器,看看到底发生了什么。
从IL中可以看到,真的就是编译器的语法糖,本质上都是在ctor中初始化的,所以说,看问题千万不要看表面。
注:Stsfld 用来自计算堆栈的值替换静态字段的值。


猜你喜欢
- 前言在之前我们分析 Tomcat catalina.bat 原理解析 时候,我们发现在启动tomcat的参数中存在 -Djava.
- 本文实例为大家分享了Java网络编程TCP实现文件上传的具体代码,供大家参考,具体内容如下上一篇博客,用网络编程TCP 实现聊天,这次实现文
- 一、前言Hello,又见面了,今天分享如何使用Unity制作计算器,难度中等,可以用来学习,或者当成其他项目的小组件导入。当然,也可以导出来
- 一、开篇说起 AOP 小伙伴们肯定很熟悉,无论是 JDK * 或者是 CGLIB 等,其底层都是通过操作 Java 字节码来实现代理。常
- 一. 简介 SQLite数据库是一个轻量级的DBMS(数据库管理系统)。SQLite使用单个文件存储数据,Android标准库包含SQLit
- 目录前言connectTimeout:callTimeout:pingIntervalwriteTimeoutreadTimeout总结前言
- 前言在开发 Flutter 应用程序时,我们需要有一个组件来管理全局设置,包括主题、导航和路由。这就是 MaterialApp 的用途。作为
- 本实例实现在jsp页面实现查询全国城市天气预报的功能,供大家参考,具体内容如下实例目录:实现效果:具体思路:从和风天气api那里取得具体城市
- 什么是Monkey?Monkey是Android SDK提供的一个命令行工具,可以简单方便的发送伪随机的用户事件流,对Android APP
- Process类的作用是对系统进程进行管理,我们使用Process类中的一些方法结合Winform开发个简单的进程管理器: 在使用Proce
- 本文分析了Android实现换肤的两种思路。分享给大家供大家参考,具体如下:这里来了解换肤实现及不同方案的差异和使用场合。一、从功能上划分1
- 本文介绍了Java中常见死锁与活锁的实例详解,分享给大家,具体如下:顺序死锁:过度加锁,导致由于执行顺序的原因,互相持有对方正在等待的锁资源
- 顺序结构按照代码书写的顺序一行一行执行分支结构if 语句基本语法形式:if(布尔表达式){ //条件满足时执行代码
- 本文实例讲述了Android TabLayout(选项卡布局)简单用法。分享给大家供大家参考,具体如下:我们在应用viewpager的时候,
- 定义队列是 Apache RocketMQ 中消息存储和传输的实际容器,也是 Apache RocketMQ 消息的最小存储单元。 Apac
- 本文研究的主要是Collections.shuffle()方法的相关内容,下面看看具体内容。Java.util.Collections类下有
- 如何解决某个节点故障的问题?如何解决数据一致性的问题?如何解决数据倾斜的问题?CAP理论先从定义开始:C(Consistence):一致性所
- 首先,你可能会见到如下提示:File encoding is disabled because .properties file (see
- Pull解析方法给应用程序完全的控制文档该怎么样被解析。Android中对Pull方法提供了支持的API,主要是org.xmlpull.v1
- 使用IDEA编辑Web项目已经逐渐超过了使用eclipse的人数,但是IDEA对于pom.xml的执行也就是Maven方式导包支持并不是很完