我已经了解了常量和静态只读字段。我们有一些类只包含常量值。它们用于我们系统中的各种事情。所以我想知道我的观察是否正确:

对于所有公开的内容,这些常量值是否总是静态只读的?并且只对内部/受保护/私有值使用const?

你有什么建议?我甚至应该不使用静态只读字段,而应该使用财产吗?


当前回答

如果Consumer位于不同的程序集中,我将使用静态只读。将const和Consumer放在两个不同的集合中是一个很好的方法来击中自己的脚。

其他回答

我的偏好是尽可能使用const,正如前面的回答中所提到的,它仅限于字面表达或不需要求值的内容。

如果我碰到了这个限制,那么我会回退到静态只读,但有一个警告。我通常会使用带有getter和支持私有静态只读字段的公共静态属性,正如Marc在这里提到的。

需要注意的几个相关事项:

常量int a

必须初始化。初始化必须在编译时进行。

只读int a

可以使用默认值,而无需初始化。初始化可以在运行时完成(编辑:仅在构造函数内)。

Const:Const只是“常量”,它的值是常量,但在编译时是常量。并且必须为其赋值。默认情况下,常量是静态的,我们不能在整个程序中更改常量变量的值。静态只读:静态只读类型变量的值可以在运行时赋值,也可以在编译时赋值,并在运行时更改。但该变量的值只能在静态构造函数中更改。并且不能进一步改变。它只能在运行时更改一次

参考:c-sharpcorner

另外一个我不相信的区别是上面提到的:

常量和静态只读值不会在Visual Studio IDE中应用CodeLens。

static只获取财产,但会将CodeLens应用于这些属性。

我认为添加CodeLens非常有价值。

注意:当前正在使用Visual Studio 2022。

const和readonly相似,但并不完全相同。

const字段是一个编译时常量,意味着该值可以在编译时计算。只读字段支持在构造类型期间必须运行某些代码的其他场景。构造后,无法更改只读字段。

例如,const成员可用于定义以下成员:

struct Test
{
    public const double Pi = 3.14;
    public const int Zero = 0;
}

因为像3.14和0这样的值是编译时间常数。然而,请考虑这样的情况:您定义了一个类型,并希望提供它的一些预制实例。例如,您可能希望定义一个Color类,并为常见颜色(如黑色、白色等)提供“常量”。不可能使用const成员来实现这一点,因为右侧不是编译时常量。可以对常规静态成员执行此操作:

public class Color
{
    public static Color Black = new Color(0, 0, 0);
    public static Color White = new Color(255, 255, 255);
    public static Color Red   = new Color(255, 0, 0);
    public static Color Green = new Color(0, 255, 0);
    public static Color Blue  = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}

但是,没有什么可以阻止Color的客户破坏它,可能是通过交换黑白值。不用说,这会给Color类的其他客户端带来恐慌。“只读”功能解决了这种情况。

通过在声明中简单地引入readonly关键字,我们保留了灵活的初始化,同时防止了客户机代码乱来。

public class Color
{
    public static readonly Color Black = new Color(0, 0, 0);
    public static readonly Color White = new Color(255, 255, 255);
    public static readonly Color Red   = new Color(255, 0, 0);
    public static readonly Color Green = new Color(0, 255, 0);
    public static readonly Color Blue  = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}

有趣的是,const成员总是静态的,而只读成员可以是静态的,也可以不是静态的,就像常规字段一样。

可以将一个关键字用于这两个目的,但这会导致版本控制问题或性能问题。假设我们对这个(const)使用了一个关键字,一个开发人员写道:

public class A
{
    public static const C = 0;
}

而另一位开发人员编写的代码依赖于a:

public class B
{
    static void Main() => Console.WriteLine(A.C);
}

现在,生成的代码是否可以依赖于A.C是一个编译时间常数这一事实?也就是说,A.C的使用是否可以简单地用值0代替?如果你对此说“是”,那么这意味着A的开发者不能改变A.C的初始化方式——这在未经许可的情况下束缚了A的开发者的双手。

如果你对这个问题说“不”,那么就会错过一个重要的优化。也许A的作者肯定A的C值永远为零。const和readonly的使用允许A的开发人员指定意图。这有助于更好的版本控制行为和更好的性能。