C# ';静态只读';与';常数';

C# ';静态只读';与';常数';,c#,constants,C#,Constants,我已经阅读了有关const和static readonly字段的内容。我们有一些只包含常量值的类。它们用于我们系统中的各种事情。所以我想知道我的观察是否正确: 对于所有公共内容,这些常量值是否应始终为静态只读?并且仅对内部/受保护/私有值使用const 你推荐什么?我应该甚至不使用静态只读字段,而是使用属性吗?公共静态只读字段有点不寻常公共静态属性(只有一个get)更常见(可能有一个私有静态只读字段支持) const值直接烧入调用站点;这是一把双刃剑: 如果该值是在运行时获取的,可能是从配置中

我已经阅读了有关
const
static readonly
字段的内容。我们有一些只包含常量值的类。它们用于我们系统中的各种事情。所以我想知道我的观察是否正确:

对于所有公共内容,这些常量值是否应始终为静态只读?并且仅对内部/受保护/私有值使用
const


你推荐什么?我应该甚至不使用
静态只读
字段,而是使用属性吗?

公共静态只读
字段有点不寻常<代码>公共静态属性(只有一个
get
)更常见(可能有一个
私有静态只读
字段支持)

const
值直接烧入调用站点;这是一把双刃剑:

  • 如果该值是在运行时获取的,可能是从配置中获取的,那么它是无用的
  • 如果更改常量的值,则需要重新生成所有客户端
  • 但它可以更快,因为它避免了方法调用
  • …有时可能已经被JIT内联了
如果该值将永远不会改变,则常数很好-
为零
等,使常数合理;p除此之外,
静态
属性更常见。

需要注意的一点是const仅限于基本类型/值类型(字符串除外)。

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

  • 必须初始化
  • 初始化必须在编译时进行
只读int a

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

我倾向于尽可能使用常量,正如前面的答案中所提到的,它仅限于字面表达式或不需要计算的东西


如果我遇到了这个限制,那么我会退回到静态只读(static readonly)
,但有一个警告。正如Marc提到的,我通常会使用带有getter和backingprivate static readonly字段的公共静态属性。

如果使用者位于不同的程序集中,我会使用
static readonly
。将
const
和使用者放在两个不同的程序集中是一个很好的方法。

只读
关键字与
const
关键字不同。
const
字段只能在声明字段时初始化。
readonly
字段可以在声明或构造函数中初始化。因此,
readonly
字段可以具有不同的值,具体取决于所使用的构造函数。此外,虽然
const
字段是编译时常量,但
readonly
字段可用于运行时常量

Const:Const只不过是“常量”,一个值在编译时为常量的变量。必须给它赋值。默认情况下,常量是静态的,我们不能在整个程序中更改常量变量的值

静态只读:静态只读类型变量的值可以在运行时赋值,也可以在编译时赋值,并在运行时更改。但是这个变量的值只能在静态构造函数中更改。不能再改变了。它在运行时只能更改一次


参考资料:

这只是对其他答案的补充。我将不再重复(四年后现在)

在某些情况下,常量和非常量具有不同的语义。例如:

const int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}
打印出
True
,而:

static readonly int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}
写入
False

原因是该方法有两个重载,一个重载接受
short
System.Int16
),另一个重载接受
对象(
System.object
)。现在的问题是,我的
y
参数是否适用一个或两个

y
是编译时常量(literal)时,
const
情况下,如果
int
是常量,则必须存在从
int
short
的隐式转换,并且前提是C#编译器验证其值是否在
short
的范围内(即
42
是)。请参见C语言规范中的。因此,必须考虑这两种重载。首选重载
Equals(short)
(任何
short
都是
对象,但并非所有
对象都是
short
)。因此,将
y
转换为
short
,并使用该重载。然后,
Equals
比较两个相同值的
short
,得到
true

y
不是常数时,不存在从
int
short
的隐式转换。这是因为一般来说,
int
可能太大,无法装入
短的
。(显式转换确实存在,但我没有说
Equals((短)y)
,因此这不相关。)我们看到只有一个重载适用,
Equals(object)
一个。因此,
y
被装箱到
对象
。然后,
Equals
将比较
System.Int16
System.Int32
,由于运行时类型甚至不一致,这将产生
false


我们得出结论,在某些(罕见的)情况下,将
常量
类型成员更改为
静态只读
字段(或其他方式,如果可能的话)可以更改程序的行为。

常量
只读
类似,但它们并不完全相同

const
字段是一个compi
struct Test
{
    public const double Pi = 3.14;
    public const int Zero = 0;
}
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);
}
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);
}
public class A
{
    public static const C = 0;
}
public class B
{
    static void Main() => Console.WriteLine(A.C);
}
public const DateTime dt = DateTime.Today;  //throws compilation error
public const string Name = string.Empty;    //throws compilation error
public static readonly string Name = string.Empty; //No error, legal
public const decimal ProgramVersion = 2.3;
[HttpTrigger(AuthorizationLeve.Anonymous,  HttpMethods.Get)] // COMPILE ERROR: static readonly, 
[HttpTrigger(AuthorizationLeve.Anonymous,  "GET")] // STRING
public class HttpConstants
{
    public const string Get = "GET";
}

[HttpTrigger(AuthorizationLeve.Anonymous,  HttpConstants.Get)] // Compile FINE!
private const int Total = 5;
private static readonly int GripKey = Animator.StringToHash("Grip");
private const int GripKey = Animator.StringToHash("Grip");