C#中的静态常量(const)和动态常量(static和readonly)用法和区别
C#中有两种常量类型,分别为readonly(运行时常量)与const(编译时常量),本文将就这两种类型的不同特性进行比较并说明各自的适用场景。
工作原理
readonly为运行时常量,程序运行时进行赋值,赋值完成后便无法更改,因此也有人称其为只读变量。
const为编译时常量,程序编译时将对常量值进行解析,并将所有常量引用替换为相应值。
下面声明两个常量:
public static readonly int A = ; //A为运行时常量
public const int B = ; //B为编译时常量
下面的表达式:
int C = A + B;
经过编译后与下面的形式等价:
int C = A + ;
可以看到,其中的const常量B被替换成字面量3,而readonly常量A则保持引用方式。
声明及初始化
readonly常量只能声明为类字段,支持实例类型或静态类型,可以在声明的同时初始化或者在构造函数中进行初始化,初始化完成后便无法更改。
const常量除了可以声明为类字段之外,还可以声明为方法中的局部常量,默认为静态类型(无需用static修饰,否则将导致编译错误),但必须在声明的同时完成初始化。
数据类型支持
由于const常量在编译时将被替换为字面量,使得其取值类型受到了一定限制。const常量只能被赋予数字(整数、浮点数)、字符串以及枚举类型。下面的代码无法通过编译:
public const DateTime D = DateTime.MinValue;
改成readonly就可以正常编译:
public readonly DateTime D = DateTime.MinValue;
可维护性
readonly以引用方式进行工作,某个常量更新后,所有引用该常量的地方均能得到更新后的值。
const的情况要稍稍复杂些,特别是跨程序集调用:
public class Class1
{
public static readonly int A = ; //A为运行时常量
public const int B = ; //B为编译时常量
} public class Class2
{
public static int C = Class1.A + Class1.B; //变量C的值为A、B之和
} Console.WriteLine(Class2.C); //输出"5"
假设Class1与Class2位于两个不同的程序集,现在更改Class1中的常量值:
public class Class1
{
public static readonly int A = ; //A为运行时常量
public const int B = ; //B为编译时常量
}
编译Class1并部署(注意:这时并没有重新编译Class2),再次查看变量C的值:
Console.WriteLine(Class2.C); //输出"7"
结果可能有点出乎意料,让我们来仔细观察变量C的赋值表达式:
public static int C = Class1.A + Class1.B;
编译后与下面的形式等价:
public static int C = Class1.A + ;
因此不管常量B的值如何变,对最终结果都不会产生影响。虽说重新编译Class2即可解决这个问题,但至少让我们看到了const可能带来的维护问题。
性能比较
const直接以字面量形式参与运算,性能要略高于readonly,但对于一般应用而言,这种性能上的差别可以说是微乎其微。
适用场景
在下面两种情况下:
a.取值永久不变(比如圆周率、一天包含的小时数、地球的半径等)
b.对程序性能要求非常苛刻
可以使用const常量,除此之外的其他情况都应该优先采用readonly常量。
C#中的static 和Java中的static
简单,两者用法完全是一致的。从两方面讨论:
1. 变量是属于类的,不是实例级别的。只能通过类名调用,不能通过实例调用。
2. 如果在定义时就赋值了,那么在类初始化的时候,最先完成所有静态变量的赋值。但是要注意,所有静态变量的初始化顺序是无法确定的。
C# 中的const 和Java中的finnal
很长一段时间我一直认为两者是相同的作用,无非是变量初始化后不能更改,即只能在定义时或者构造函数中赋值。然而这仅仅只是片面的,下面将为大家详细分析:
1.修饰变量
准确的说C#中的const 等价于 Java中的static final,也就是说,Java中final不具有static的功能。而C#中的const具有static的功能。因此在C#中 public static const string 等将于 public const string。
2.修饰类和方法
此时Java中的final类似C#中的sealed,就是说,final修饰的类不能被继承,final修饰的方法不能被覆盖。
而C#中的const不能修饰类和方法。
问题:
1. 私有静态成员的作用(private static 变量)
字面表示私有的,类外不能使用;静态的,全局变量。看上去很矛盾,又不能被类外使用,要全局的有什么用。问得好,类中全局也是很有意义的,例如 private static int a = 5,那么就可以保证变量a在类的初始化过程中将被优先初始化(在构造函数执行之前)。这样如果对象A的初始化需要对象B的实例,那么就可以用这种申明,以保证在类A在构造函数中能够使用类B的实例。同时private又能够保证类B的实例只能在类A中使用,起到很好的密封作用。
2. 私有最终成员作用(private final 变量)
在类构造函数完成前必须对该成员完成初始化,一旦定义不许更改;该成员只能在本类中使用。实例,子类中都不能使用。
private static final修饰的成员在申明的时就被赋值,保证在构造函数中可以被使用,一个被private static final修饰的成员通常表示其他组件的一个实例,且变量是类中的全局变量。
private final 修饰的成员在构造中被赋值,表示它是该类全局的私有成员变量,且该类的构造需要传入他们的初始值,才能完成类的初始化。
C# const和static readonly区别
const: 用const修饰符声明的成员叫常量,是在编译期初始化并嵌入到客户端程序
static readonly: 用static readonly修饰符声明的成员依然是变量,只不过具有和常量类似的使用方法:通过类进行访问、初始化后不可以修改。但与常量不同的是这种变量是在运行期初始化。
C# const和static readonly区别示例:
using System;
using System.Collections.Generic;
using System.Text; namespace Example02Lib
{
public class Class1
{
public const String strConst = "Const";
public static readonly String strStaticReadonly = "StaticReadonly";
//public const String strConst = "Const Changed";
//public static readonly String strStaticReadonly = "StaticReadonly Changed";
}
}
客户端代码:
using System;
using System.Collections.Generic;
using System.Text;
using Example02Lib;
namespace Example02
{
class Program
{
static void Main(string[] args)
{
//修改Example02中Class1的strConst初始值后,只编译Example02Lib项目
//然后到资源管理器里把新编译的Example02Lib.dll拷贝Example02.exe所在的目录, 执行Example02.exe
//切不可在IDE里直接调试运行因为这会重新编译整个解决方案!!
//可以看到strConst的输出没有改变,而strStaticReadonly的输出已经改变
//表明Const变量是在编译期初始化并嵌入到客户端程序,而StaticReadonly是在运行时初始化的
Console.WriteLine("strConst : {0}", Class1.strConst);
Console.WriteLine("strStaticReadonly : {0}",
Class1.strStaticReadonly);
Console.ReadLine();
}
}
}
修改后的示例:
using System;
using System.Collections.Generic;
using System.Text; namespace Example02Lib
{
public class Class1
{
//public const String strConst = "Const";
//public static readonly String strStaticReadonly = "StaticReadonly";
public const String strConst = "Const Changed";
public static readonly String strStaticReadonly = "StaticReadonly Changed";
}
}
C#中的静态常量(const)和动态常量(static和readonly)用法和区别的更多相关文章
- 在Linux中创建静态库.a和动态库.so
转自:http://www.cnblogs.com/laojie4321/archive/2012/03/28/2421056.html 在Linux中创建静态库.a和动态库.so 我们通常把一些公用 ...
- C# 静态常量(const)动态常量(static、readonly)用法区别
C# 常量的命名方法 一个低级错误 readonly.const 代码 使用方式 支持类型 维护性 性能比较 优先使用 C# Static 与 Java Static C# Const 与 Java ...
- 017 Java中的静态代理、JDK动态代理、cglib动态代理
一.静态代理 代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理. 静态代理由业务实现类.业务代理类两部分组成.业务实现类负责实现主要的业务方法,业 ...
- DelphiXe 中静态数组TByteArray和动态数组TBytes /array of byte 的区别
在应用中发现静态数组和动态数组是有区别的: procedure TForm1.Button1Click(Sender: TObject);var RsltStream: TMemoryStream; ...
- in C#,编译型常量(const)和运行时常量(readonly)
readonly 关键字与 const 关键字不同. const 字段只能在该字段的声明中初始化. readonly 字段可以在声明或构造函数中初始化. 因此,根据所使用的构造函数, readonly ...
- c# 编译期常量const和运行时常量readonly
注意:const编译期常量是编译的时候就确定的,可以查看IL代码,是写死的.如果另一个程序集引用后,该程序集没有进行编译,则值不会改变. 看效果: 项目中有2个程序集: 其中:常量在这个程序集中定义并 ...
- 【转】C中的静态存储区和动态存储区
一.内存基本构成 可编程内存在基本上分为这样的几大部分:静态存储区.堆区和栈区.他们的功能不同,对他们使用方式也就不同. 静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个 ...
- Vue-cli中的静态资源管理(src/assets和static/的区别)
资源打包 为了回答这个问题,我们需要了解webpack是如何处理静态资源的.在所有的*.vue文件中你所有的templates 和CSS 都被vue-html-loader 和css-loader 查 ...
- Python中的静态属性、实例属性、静态方法、实例方法之间的区别
随机推荐
- 20155214 2016-2017-2 《Java程序设计》第3周学习总结
20155214 2016-2017-2 <Java程序设计>第3周学习总结 教材学习内容总结 Chapter4 一个原始码中可以有多个类定义,但只能有一个公开类,且文档中的主文档名必须与 ...
- 20155234 实验二 Java面向对象程序设计
实验二 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 实验步骤 (一)单元测试 ...
- 20155234 2016-2017-2 《Java程序设计》第2周学习总结
20155234 2006-2007-2 <Java程序设计>第2周学习总结 教材学习内容总结 %%:表示字符串中的%. %d:以十进制整数格式输出 %f:以十进制浮点式格式输出 %e(% ...
- 微信小程序居中代码
html页面: { text-align:center; } wxss页面: { width: 100%; height: 100%; display: flex; justify-content: ...
- 【MongoDB】如何注册windows服务
一.为什么要注册windows服务 mongodb启动比较麻烦,每次都要cmd去开启.注册windows服务,可以设置开机启动,比较友好. 二.如何注册windows服务 1.安装mongodb 2. ...
- Redis实现之客户端
客户端 Redis服务器是典型的一对多服务器程序:一个服务器可以与多个客户端建立网络连接,每个客户端可以向服务器发送命令请求,而服务器则接收并处理客户端发送的命令请求,并向客户端返回命令回复.通过使用 ...
- [转载]A cycle was detected in the build path of project
解决Eclipse中Java工程间循环引用而报错的问题 如果我们的项目包含多个工程(project),而它们之间又是循环引用的关系,那么Eclipse在编译时会抛出如下一个错误信息: “A cycle ...
- PHP版本的讲解
原文地址:http://dev.meettea.com/show-90-1.html 最近发现很多PHP程序员对PHP版本知识了解不是很清楚,其中不乏PHP产品主力开发人员. PHP版本主要分三支:P ...
- 音频分析框架pyAudioAnalysis文档
“ pyAudioAnalysis是一个非常好用且强大的音频分析开源工具,能实现音频的特征提取.分类和回归模型的训练和执行,以及其他一些实用的功能.此外,本文档并非直译,也有部分比较简略,可以结合源码 ...
- 《Cocos2d-x游戏开发实战精解》学习笔记1--在Cocos2d中显示图像
Cocos2d-x中的图像是通过精灵类来显示的.在Cocos2d-x中游戏中的每一个角色.怪物.道具都可以理解成是一个精灵,游戏背景作为一种特殊的单位将其理解成是一个精灵也没有什么不妥.在源文件本章目 ...