0Pricing
C# Academy · 课时

常量与 readonly 字段

区分 const 与 static readonly。

常量与 readonly 字段 是 CoddyKit 上的免费 C# Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。

让值保持固定的两种方式

C# 提供 const 和 readonly,用于表示不应更改的值。它们看起来相似,但行为却非常不同。本课将比较二者。

using System;

class Config
{
    public const double Pi = 3.14159;
    public static readonly DateTime StartedAt = DateTime.Now;
}

class Program
{
    static void Main()
    {
        Console.WriteLine("Pi = " + Config.Pi);
    }
}

const:编译时常量

声明 const 时必须为其赋予字面量值,并且该值会在编译时直接嵌入。它会隐式成为静态成员。

using System;

class Circle
{
    public const double Pi = 3.14159;

    public static double Area(double r) => Pi * r * r;
}

class Program
{
    static void Main()
    {
        Console.WriteLine(Circle.Area(2).ToString("0.00"));
    }
}

const 必须是字面量

由于 const 会在编译时解析,因此它只能保存常量表达式:数字、字符串、布尔值或其他 const。

using System;

class Limits
{
    public const int MaxRetries = 3;
    public const int Timeout = MaxRetries * 1000;   // const expression OK
}

class Program
{
    static void Main()
    {
        Console.WriteLine(Limits.MaxRetries + ", " + Limits.Timeout);
    }
}

readonly:运行时常量

readonly 字段只能设置一次,可以在声明时或构造函数中设置,之后便不能更改。它的值可以在运行时计算。

using System;

class Session
{
    public readonly string Id;

    public Session(string id)
    {
        Id = id;   // allowed: inside constructor
    }
}

class Program
{
    static void Main()
    {
        var s = new Session("abc-123");
        Console.WriteLine("Session: " + s.Id);
    }
}

readonly 可以使用运行时值

与 const 不同,readonly 字段可以保存只有在程序运行时才能确定的值,例如生成的 id 或当前时间。

using System;

class Order
{
    public readonly Guid OrderId;

    public Order()
    {
        OrderId = Guid.NewGuid();
    }
}

class Program
{
    static void Main()
    {
        var o = new Order();
        Console.WriteLine("Has id: " + (o.OrderId != Guid.Empty));
    }
}

静态 readonly

将 static readonly 结合使用,可以表示一个在运行时计算一次、供整个类使用的值。当值不是字面量时,这通常是替代 const 的方式。

using System;

class AppInfo
{
    public static readonly string[] Roles = { "admin", "user", "guest" };
}

class Program
{
    static void Main()
    {
        Console.WriteLine("Roles: " + Roles());
    }

    static int Roles() => AppInfo.Roles.Length;
}

常量跨程序集为何可能带来风险

由于 const 值会在编译时内联到调用代码中,因此更改库中的公共 const 后,必须重新编译所有调用方。使用 static readonly 可以避免这一问题。

using System;

class Lib
{
    public const int Version = 2;              // inlined into callers
    public static readonly int Build = 100;     // read at runtime
}

class Program
{
    static void Main()
    {
        Console.WriteLine(Lib.Version + "." + Lib.Build);
    }
}

两者都不能重新赋值

初始化后,const 和 readonly 字段都不能再更改。尝试这样做会导致编译错误。

using System;

class Demo
{
    public const int A = 10;
    public readonly int B;

    public Demo() { B = 20; }
    // A = 11;  // would not compile
    // B = 21;  // would not compile outside constructor
}

class Program
{
    static void Main()
    {
        var d = new Demo();
        Console.WriteLine(Demo.A + ", " + d.B);
    }
}

如何在两者之间选择

对于真正不会改变的字面量(圆周率、MaxInt),请使用 const。当值在运行时计算,或可能因实例而异时,请使用 readonly。

using System;

class Physics
{
    public const double Gravity = 9.81;          // universal literal
    public readonly double Mass;                  // per object

    public Physics(double mass) { Mass = mass; }
    public double Weight() => Mass * Gravity;
}

class Program
{
    static void Main()
    {
        var p = new Physics(10);
        Console.WriteLine("Weight: " + p.Weight());
    }
}

readonly 引用注意事项

readonly 锁定的是字段,而不是它所指向的对象。readonly 列表引用不能重新赋值,但其内容仍然可以改变。

using System;
using System.Collections.Generic;

class Cart
{
    public readonly List<string> Items = new List<string>();
}

class Program
{
    static void Main()
    {
        var c = new Cart();
        c.Items.Add("Pen");   // allowed: mutating the object
        c.Items.Add("Book");
        Console.WriteLine("Items: " + c.Items.Count);
    }
}

综合运用

典型的类会使用 const 保存固定字面量,并使用 readonly 保存对象构造时针对每个实例确定的值。

using System;

class Account
{
    public const decimal MinBalance = 0m;
    public readonly string Owner;

    public Account(string owner)
    {
        Owner = owner;
    }
}

class Program
{
    static void Main()
    {
        var a = new Account("Rin");
        Console.WriteLine(a.Owner + " min=" + Account.MinBalance);
    }
}

快速检查

请测试您对常量与 readonly 区别的理解。

回顾

const 是编译时字面量,隐式为静态成员,并会内联到调用方中。readonly 只能在声明时或构造函数中设置一次,但可以使用运行时值。真正的字面量请使用 const,运行时计算的共享值请使用 static readonly,并记住 readonly 锁定的是引用,而不是对象。

using System;

class Demo
{
    public const int Max = 100;
    public readonly int Created;
    public Demo(int c) { Created = c; }
}

class Program
{
    static void Main()
    {
        var d = new Demo(7);
        Console.WriteLine(Demo.Max + ", " + d.Created);
    }
}

常见问题解答

「常量与 readonly 字段」课时是免费的吗?

是的 — 「常量与 readonly 字段」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。

「常量与 readonly 字段」这节课中我会学到什么?

区分 const 与 static readonly。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C# Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「常量与 readonly 字段」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C# Academy 课中编写并运行代码吗?

能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 静态方法与字段
  2. 用于实用功能的静态类
  3. 常量与 readonly 字段
  4. 静态设计与实例设计
← 返回 C# Academy