zoukankan      html  css  js  c++  java
  • 《CLR Via C# 第3版》笔记之(七) const和readonly

    C#中经常用const或者readonly来定义不可改变常量,那么如何使用它们呢?

    主要内容:

    • const和readonly的区别
    • readonly的补充说明

    1. const和readonly的区别

    主要的区别在于 const是在编译时确定值的,readonly是在运行时确定值的。

    因此,用const修饰的字段,必须在定义的时候就赋值,否则编译器报错。

    而readonly修饰的字段除了可以在定义时赋值以外,还可以在构造函数中赋值。

    验证的代码如下:

    using System;
    
    namespace Test7
    {
        public class CLRviaCSharp_7
        {
            const string cValue = "const";
            readonly string rValue;
    
            public CLRviaCSharp_7()
            {
                rValue = "readonly";
            }
    
            static void Main(string[] args)
            {
                CLRviaCSharp_7 test7 = new CLRviaCSharp_7();
    
                Console.WriteLine("cValue=" + CLRviaCSharp_7.cValue);
                Console.WriteLine("rValue=" + test7.rValue);
    
                Console.ReadKey(true);
            }
        }
    }

    编译后用ILSpy查看IL代码如下:

    .class public auto ansi beforefieldinit CLRviaCSharp_7
    	extends object
    {
    	// Fields
    	.field private static literal string cValue = "const"
    	.field private initonly string rValue
    
    	// Methods
    	.method public hidebysig specialname rtspecialname 
    		instance void .ctor () cil managed 
    	{
    		// Method begins at RVA 0x20c7
    		// Code size 21 (0x15)
    		.maxstack 8
    
    		IL_0000: ldarg.0
    		IL_0001: call instance void object::.ctor()
    		IL_0006: nop
    		IL_0007: nop
    		IL_0008: ldarg.0
    		IL_0009: ldstr "readonly"
    		IL_000e: stfld string class Test7.CLRviaCSharp_7::rValue
    		IL_0013: nop
    		IL_0014: ret
    	} // End of method CLRviaCSharp_7..ctor
    
    	.method private static hidebysig 
    		void Main (
    			string[] args
    		) cil managed 
    	{
    		// Method begins at RVA 0x20e0
    		// Code size 48 (0x30)
    		.maxstack 2
    		.entrypoint
    		.locals init (
    			[0] class Test7.CLRviaCSharp_7 test7
    		)
    
    		IL_0000: nop
    		IL_0001: newobj instance void Test7.CLRviaCSharp_7::.ctor()
    		IL_0006: stloc.0
    		IL_0007: ldstr "cValue=const"
    		IL_000c: call void [mscorlib]System.Console::WriteLine(string)
    		IL_0011: nop
    		IL_0012: ldstr "rValue="
    		IL_0017: ldloc.0
    		IL_0018: ldfld string class Test7.CLRviaCSharp_7::rValue
    		IL_001d: call string string::Concat(string, string)
    		IL_0022: call void [mscorlib]System.Console::WriteLine(string)
    		IL_0027: nop
    		IL_0028: ldc.i4.1
    		IL_0029: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey(bool)
    		IL_002e: pop
    		IL_002f: ret
    	} // End of method CLRviaCSharp_7.Main
    
    } // End of class Test7.CLRviaCSharp_7

    从Main函数中的IL_0007,我们可以看出,编译时就已经将 cValue替换为字符串"const"了,所以在Main函数中看不出使用了字段cValue

    从Main函数中的IL_0018,我们可以看出,运行时才读取 rValue的值,将其拼接到输出的字符串中。

    2. readonly的补充说明

    const和readonly虽然都可以定义常量,但是由于readonly是在运行时才确定值的,所以比const更加灵活。

    当然,readonly的性能肯定比const稍逊。(具体相差多少还没有试验过)

    readonly与const相比,使用时需要注意2点。

    2.1. readonly的字段可以通过反射来修改

    具体参见以下代码

    using System;
    using System.Reflection;
    
    namespace Test7
    {
        public class CLRviaCSharp_7
        {
            static void Main(string[] args)
            {
                ChangeReadonlyClass cr = new ChangeReadonlyClass();
                Console.WriteLine("before change, rValue=" + cr.rValue);
    
                // 利用反射来改变ChangeReadonlyClass中readonly字段的值
                FieldInfo fi =  typeof(ChangeReadonlyClass).GetField("rValue");
                fi.SetValue(cr, "rValue has changed");
                Console.WriteLine("after  change, rValue=" + cr.rValue);
    
                Console.ReadKey(true);
            }
        }
    
        public class ChangeReadonlyClass
        {
            public readonly string rValue;
    
            public ChangeReadonlyClass()
            {
                rValue = "ChangeReadonlyClass's readonly field";
            }
            
        }
    }

    运行结果如下:

    image

    2.2. readonly的字段为引用类型时,不可改变的是引用,而不是引用的对象。

    验证代码如下:

    using System;
    
    namespace Test7
    {
        public class CLRviaCSharp_7
        {
            public static readonly Char[] rValues = new Char[] { 'X', 'Y', 'Z' };
    
            static void Main(string[] args)
            {
                // 修改引用的对象,可以成功修改并运行
                rValues[0] = 'A';
                rValues[1] = 'B';
                rValues[2] = 'C';
    
                // 修改引用本身,无法编译
                rValues = new Char[] { 'A', 'B', 'C' };
    
                Console.ReadKey(true);
            }
        }
    }

    readonly并不像const那样是绝对的常量。我们在利用其灵活性的同时,也应注意它可能带来的副作用。

  • 相关阅读:
    onenote 使用手记0.3阶级
    尘埃落定:没有传说中k700i,官方只认可k700!
    【转】Ubuntu 9.10下安装Eclipse CDT 6.0
    四则运算
    文本内容统计
    《程序员修炼之道:从小工到专家》读后感(4)
    《程序员修炼之道:从小工到专家》读后感(5)
    多线程
    河北金力集团公文流转系统节选(2)
    动手动脑(6)文件和流
  • 原文地址:https://www.cnblogs.com/wang_yb/p/2092886.html
Copyright © 2011-2022 走看看