C#中的readonly

本文详细解析C#中const、static和readonly三个关键字的区别,包括它们在编译期和运行期的特性,以及如何正确使用它们以避免常见的陷阱。文章深入探讨了每个关键字的特点,并通过实例展示了它们在实际编程中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

const 定义的是静态常在对象初始化的时候赋值.以后不能改变它的值.属于编译时常量。不能用new初始化。

Readonly 是只读变量.属于运行时变量.可以在类constructor里改变它的值.不能作用于局部变量。

const 和 static 不能在一起用,它已经是静态的了。

我们都知道,const和static readonly的确非常像:通过类名而不是对象名进行访问,在程式中只读等等。在多数情况下能混用。
二者本质的差别在于,const的值是在编译期间确定的,因此只能在声明时通过常量表达式指定其值。

而static readonly,在程式中只读, 不过它是在运行时计算出其值的,所以还能通过静态构造函数来对它赋值,

readonly只能用来修饰类的field,不能修饰局部变量,也不能修饰property等其他类成员.

明白了这个本质差别,我们就不难看出下面的语句中static readonly和const能否互换了:

1. static readonly MyClass myins = new MyClass();
2. static readonly MyClass myins = null;
3. static readonly B = 10;   static readonly A = B* 20;
4. static readonly int[] constIntArray = new int[] { 1, 2, 3 };
5. void SomeFunction()
{
    const int a = 10;
    .........
}
1:不能换成const。new操作符是需要执行构造函数的,所以无法在编译期间确定
2:能换成const。我们也看到,Reference类型的常量(除了String)只能是Null。
3:能换成const。我们能在编译期间非常明确的说,A等于200。
4:不能换成const。道理和1是相同的,虽然看起来1,2,3的数组的确就是个常量。
5:不能换成readonly,readonly只能用来修饰类的field,不能修饰局部变量,也不能修饰property等其他类成员。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    //定义一个类
   class Class1
    {
        int value;
        public void ChangeValue1(int _value)
        {
            value = _value;
        }
        public void ShowValue1()
        {
            Console.WriteLine(value);
        }
    }
    //再定义一个类,把第一个类作为变量
    class Class2
    {
        readonly Class1 class1;//注意是readonly

        public Class2() { class1 = new Class1(); }

        public void ChangeValue2(int _value)
        {
            class1.ChangeValue1(_value);//
        }
    }
    class Program
    {
        static void Main(string[] args)
        {



        }
    }
}

我们看到虽然class1这个字段是readonly的,但是可以使用方法来改变value的值。似乎这个“只读”失去了意义,因为可以修改它的值的话还叫什么“只读”呢?

非也!

从上面的代码中我们可以看到,class1的类型是Class1,是一个引用类型。而引用类型是必须用new关键字为它分配了一块内存以后它才能在后续代码中工作的。也就是说

,class1这个变量仅仅是一块内存地址罢了。

也就是说,这里的“readonly” class1只是无法再重新更改它的引用,但它所引用对象的属性是可以改变的。

那么为什么不用const呢?还是因为class1是引用,是动态分配内存的,不可能在编译阶段就确定它的地址,这点和值类型(包括string)是完全不一样的。

综上所述,可以得出结论: readonly修饰的字段,其初始化仅是固定了其引用(地址不能修改),但它引用的对象的属性是可以更改的。

所以,大胆放心的用readonly吧,这样还可以防止不必要的再赋值,保证了这个对象的安全性。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    //定义一个类
   class Class1
    {
        public readonly int value;

        public Class1(int _value)
        {
            value = _value;//right,只能通过构造函数来对value赋值
        }

        public void ChangeValue1(int _value)
        {
            value = _value;//error
        }
       
    }
  
    class Program
    {
        static void Main(string[] args)
        {

            Class1 one = new Class1(2);
            int b = 2;
            one.value = b;//error
        }
    }
}




<think>首先,用户的问题是关于C#中的readonly关键字,询问其用途和用法。我需要基于系统级指令和用户可见层的要求来构建回答。 系统级指令: - 所有行内数学表达式使用$...$格式。但这个问题是关于C#编程的,没有数学表达式,所以可能不需要这个。 - 独立公式使用$$...$$,同样,这里可能不适用。 - LaTeX语法正确:确保任何公式正确。 - 使用中文回答:整个回答必须用中文。 - 生成相关问题:在回答末尾添加相关问题。 - 回答中引用的段落末尾添加引用标识,如[^1]。 用户可见层: - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠:基于提供的引用内容。 提供的引用内容: - 引用[1]: 解释了readonly关键字的要点:只能在定义时或构造函数中赋值;其他地方不能修改;只读属性只有get访问器。与const的区别:const只能在声明时初始化。 - 引用[2]: 进一步说明readonlyconst的区别:const是编译时常量;readonly可用于运行时常量;可以在声明或构造函数中初始化;示例代码。 - 引用[3]: 定义:用在类的属性上;只能在定义时或构造函数中初始化;作用:确保数据成员初始化后不能被改变。 - 引用[4]: 强调必须在字段定义时或构造函数中初始化;示例代码。 - 引用[5]: 比较conststatic readonlystatic readonly可以在静态构造函数中赋值;const在编译时获取值,static readonly在运行时。 用户的问题:C# readonly关键字的用途和用法。 我需要构建一个清晰的回答: 1. 介绍readonly关键字的用途。 2. 解释用法,包括如何初始化和限制。 3. 与const关键字的区别。 4. 提供简单示例。 5. 添加相关问题。 结构: - 开头:简要介绍readonly关键字。 - 用途:解释为什么使用它。 - 用法:详细说明如何声明和初始化。 - 区别:与const的比较。 - 示例:给出代码示例。 - 结尾:总结。 - 相关问题:生成相关问题。 使用引用:在回答中引用段落时,添加引用标识。例如,如果提到“只能在定义时或构造函数中赋值”,添加[^1]。 确保语言为中文。 大纲回答: 1. **介绍**:C#中的readonly关键字用于声明只读字段,确保字段在初始化后不能被修改。 2. **用途**: - 保证数据在初始化后不可变,提高代码安全性和可维护性。 - 例如,用于配置值或常量但需要在运行时确定的场景[^1][^3]。 3. **用法**: - 只能在声明时或类的构造函数中初始化[^1][^3][^4]。 - 不能在类的外部或其他方法中修改[^1]。 - 对于属性,readonly字段通常只有get访问器,没有set[^1]。 4. **与const的区别**: - const是编译时常量,必须在声明时初始化[^1][^2]。 - readonly是运行时常量,可以在声明或构造函数中初始化,允许在运行时赋值[^2][^5]。 - 示例:const字段值在编译时固定;readonly字段值可以在运行时计算[^2]。 5. **示例代码**: - 提供一个简单的C#类示例。 - 如:public class MyClass { public readonly int MyField; public MyClass() { MyField = 10; } } [^4]。 6. **总结**:readonly关键字提供了一种在初始化后保护字段不被修改的方式,适用于需要在运行时确定值的常量。 7. **相关问题**:生成3-5个相关问题。 相关问题想法: 1. 如何在C#中正确使用readonly关键字? 2. readonlyconst的区别是什么? 3. 在哪些场景下应该优先使用readonly而不是const? 4. readonly字段可以用于静态字段吗?如何初始化? 5. 使用readonly关键字有什么潜在缺点? 确保回答基于引用,真实可靠。</think>### C# readonly关键字的用途和用法 在C#中,`readonly`关键字用于声明只读字段(readonly field),其主要目的是确保字段在初始化后不能被修改,从而提高代码的安全性和可维护性。以下我将基于C#官方文档和最佳实践,逐步解释其用途和用法。内容参考了多个可靠来源,确保回答准确可靠[^1][^2][^3]。 #### 1. **readonly关键字的用途** - **保证数据不可变性**:`readonly`确保字段一旦初始化后,其值在对象的生命周期内保持不变。这适用于需要保护数据不被意外修改的场景,例如配置参数、常量值或需要在运行时确定的固定值[^1][^3]。 - **提高代码健壮性**:通过限制字段的修改,减少错误(如无效状态变更),尤其在多线程环境中增强安全性[^2]。 - **与const的区别**:`readonly`是运行时常量,允许在运行时赋值;而`const`是编译时常量,必须在声明时初始化且值在编译时固定[^2][^5]。例如: - `const`:`public const int MaxCount = 100;` // 值在编译时确定 - `readonly`:`public static readonly uint Timestamp = (uint)DateTime.Now.Ticks;` // 值在运行时计算[^2] #### 2. **readonly关键字的使用方法** - **初始化规则**: - `readonly`字段只能在**声明时**或**类的构造函数中**初始化[^1][^3][^4]。 - 不能在类的外部、普通方法或其他地方修改其值[^1]。 - 示例:声明时初始化或在构造函数中赋值。 ```csharp public class MyClass { // 声明时初始化 public readonly int Field1 = 10; // 在构造函数中初始化 public readonly int Field2; public MyClass(int value) { Field2 = value; // 合法:在构造函数中赋值 } public void UpdateField() { // Field2 = 20; // 错误:不能在非构造函数方法中修改 } } ``` - **适用场景**: - **实例字段**:用于类的非静态字段,每个对象可以有不同的值。 - **静态字段**:结合`static`关键字,用于静态只读字段(如`public static readonly int Age = 10;`)。静态只读字段可以在静态构造函数中初始化[^5]。 - **属性中的使用**:`readonly`通常用于字段,但可通过只读属性实现类似效果(只提供get访问器)[^1][^3]。例如: ```csharp public class Sample { private readonly int _value; public int Value => _value; // 只读属性,无set访问器 } ``` #### 3. **关键注意事项** - **赋值限制**:如果未在声明时初始化,必须在所有构造函数中赋值,否则编译错误[^4]。 - **运行时常量**:`readonly`字段的值在运行时确定,允许使用动态值(如当前时间),而`const`仅限于编译时常量[^2][^5]。 - **性能影响**:与`const`相比,`readonly`字段在运行时解析,可能略慢,但提供更大的灵活性[^5]。 #### 4. **完整示例** 以下代码展示`readonly`的典型用法,包括实例字段和静态字段: ```csharp using System; public class Point { // 声明时初始化 public readonly int X = 5; // 构造函数中初始化 public readonly int Y; // 静态只读字段 public static readonly int Z; // 静态构造函数(用于静态字段初始化) static Point() { Z = 15; // 合法:静态只读字段在静态构造函数中赋值 } public Point(int y) { Y = y; // 合法:在实例构造函数中赋值 } } class Program { static void Main() { Point p = new Point(10); Console.WriteLine($"X: {p.X}, Y: {p.Y}, Z: {Point.Z}"); // p.X = 20; // 错误:不能在外部修改 } } // 输出:X: 5, Y: 10, Z: 15 ``` #### 总结 `readonly`关键字在C#中用于创建只读字段,确保数据在初始化后不可变。它比`const`更灵活,支持运行时赋值,适用于需要保护数据完整性的场景。正确使用`readonly`能提升代码可靠性,但需注意初始化规则[^1][^2][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值