我已经阅读了有关const
和static readonly
字段的信息。我们有一些仅包含常量值的类。用于我们系统中的各种事物。所以我想知道我的观察是否正确:
这些常量值是否应该对所有公共内容始终保持static readonly
?并且仅将const
用于内部 / 受保护 / 私有值吗?
你有什么建议吗?我是否应该甚至不使用static readonly
字段,而应该使用属性?
public static readonly
字段有点不寻常; public static
属性(只有get
)会更常见(可能由private static readonly
字段支持)。
const
值直接刻录到调用站点中;这是双刃的:
如果该值永远不变,则 const 很好 - Zero
等可以使 const 变得合理; p 除此之外, static
属性更为常见。
如果使用者在不同的程序集中,我将使用static readonly
。将const
和Consumer放在两个不同的程序集中是一个不错的选择 。
const int a
只读 int
这只是对其他答案的补充。我不再重复(现在是四年后)。
在某些情况下, 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
。
原因是方法x.Equals
有两个重载,一个重载为short
( System.Int16
),一个重载为object
( System.Object
)。现在的问题是我的y
参数是否适用于其中之一。
当y
是编译时常量(文字)(即const
情况)时,重要的是,确实存在从 int
到 short
的隐式转换,前提是int
是常量,并且 C#编译器验证其值在short
范围(即42
)。请参见 C#语言规范中的隐式常量表达式转换 。因此,必须考虑两个过载。首选重载Equals(short)
(任何short
是一个object
,但并非所有object
都是short
)。因此y
转换为short
,并且使用了重载。然后, Equals
比较两个相同值的short
,得到true
。
当y
不是常数时,不存在从int
到short
隐式转换。那是因为通常int
可能太大而无法放入short
。 (确实存在显式转换,但我没有说Equals((short)y)
,所以没有关系。)我们看到只有一个重载适用,而Equals(object)
适用。所以y
被装箱成object
。然后, Equals
将把System.Int16
与System.Int32
进行比较,并且由于运行时类型甚至不一致,因此将产生false
。
我们得出的结论是,在某些(罕见)情况下,将const
类型的成员更改为static readonly
字段(或在可能的情况下,以其他方式更改)可以更改程序的行为。
需要注意的一件事是const仅限于基本类型 / 值类型(字符串除外)
静态只读 :可以在运行时通过static
构造函数更改值。但不是通过成员函数。
常量 :默认为static
。不能在任何地方(Ctor,Function,运行时等,无处)更改值。
只读 :可以在运行时通过构造函数更改值。但不是通过成员函数。
您可以看一下我的仓库: C#属性类型 。
readonly
关键字与const
关键字不同。 const
字段只能在该字段的声明中初始化。 readonly
字段可以在声明中或在构造函数中初始化。因此,取决于使用的构造函数, readonly
字段可以具有不同的值。同样,虽然const
字段是编译时常量,但readonly
字段可用于运行时常量
const
和readonly
是相似的,但是它们并不完全相同。
const
字段是编译时常量,表示可以在编译时计算该值。 readonly
字段可启用其他方案,在该方案中,必须在类型构造期间运行某些代码。构造后, readonly
字段无法更改。
例如, 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 的客户使用它了,也许可以通过交换 Black 和 White 值来解决。不用说,这会使 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 成员始终是静态的,而 readonly 成员可以是静态的,也可以不是静态的,就像常规字段一样。
可以将单个关键字用于这两个目的,但这会导致版本问题或性能问题。假设一会儿,我们为此关键字(const)使用了一个关键字,并且开发人员写道:
public class A
{
public static const C = 0;
}
另一位开发人员编写了依赖于 A 的代码:
public class B
{
static void Main() => Console.WriteLine(A.C);
}
现在,生成的代码是否可以依赖 AC 是编译时常量的事实?即,AC 的使用是否可以简单地替换为值 0?如果对此说 “是”,则意味着 A 的开发人员无法更改 AC 初始化的方式 - 未经许可,这会束缚 A 的开发人员的双手。
如果您对这个问题说 “否”,那么将错过重要的优化。也许 A 的作者肯定 AC 将始终为零。 const 和 readonly 的使用允许 A 的开发人员指定意图。这样可以实现更好的版本控制行为以及更好的性能。
我的首选是尽可能使用const ,如上所述,它仅限于文字表达式或不需要求值的内容。
如果我遇到了这个限制,那么我会退一步回到静态 readonly ,但要注意一点。正如 Marc 在这里提到的,我通常会使用带有 getter 和后备私有 static readonly字段的公共静态属性。
常量:常量就是 “常量”,它的值是恒定的,但在编译时才是常量。并且必须为其分配值。默认情况下,const 是静态的,我们无法在整个程序中更改 const 变量的值。
静态只读:静态只读类型变量的值可以在运行时分配,也可以在编译时分配,并在运行时更改。但是只能在静态构造函数中更改此变量的值。并且无法进一步更改。在运行时只能更改一次
参考: c-sharpcorner