Answers:
除了明显的区别
const
VS readonly
值时声明值,该值可以动态计算,但需要在构造函数退出之前分配。在冻结之后。static
。您使用一种ClassName.ConstantName
符号来访问它们。有细微的差别。考虑在中定义的类AssemblyA
。
public class Const_V_Readonly
{
public const int I_CONST_VALUE = 2;
public readonly int I_RO_VALUE;
public Const_V_Readonly()
{
I_RO_VALUE = 3;
}
}
AssemblyB
AssemblyA
在代码中引用并使用这些值。编译后,
const
值的情况下,就像是一个查找替换,值2被“烘焙”到AssemblyB
IL中。这意味着如果明天我将I_CONST_VALUE
在未来更新到20。AssemblyB
在我重新编译之前仍然有2个。readonly
值的情况下,它类似于ref
存储位置。该值未烘焙到AssemblyB
的IL中。这意味着如果内存位置已更新,AssemblyB
则无需重新编译即可获取新值。因此,如果I_RO_VALUE
将其更新为30,则只需要构建即可AssemblyA
。不需要重新编译所有客户端。因此,如果您确信常量的值不会改变,请使用const
。
public const int CM_IN_A_METER = 100;
但是,如果您有一个可能会更改的常量(例如,精度),或者有疑问,请使用readonly
。
public readonly float PI = 3.14;
更新:Aku需要得到提及,因为他首先指出了这一点。另外,我需要在我学到的知识上加点文字。. 有效的C#-Bill Wagner
static
点似乎是最重要和有用的点consts are implicitly static
readonly
可以在构造函数外部更改变量(反射)。只是编译器试图阻止您在构造函数之外修改var。
readonly
构造函数完成后,即使通过反射也不允许更改@ mini-me 变量。运行时碰巧不执行此操作。运行时也碰巧不强制您不要更改string.Empty
为"Hello, world!"
,但是我仍然不会声称这是string.Empty
可修改的,或者代码不应该假定该string.Empty
字符串始终为零长度。
只需添加一下,对于引用类型的ReadOnly仅会使引用变为只读,而不是值。例如:
public class Const_V_Readonly
{
public const int I_CONST_VALUE = 2;
public readonly char[] I_RO_VALUE = new Char[]{'a', 'b', 'c'};
public UpdateReadonly()
{
I_RO_VALUE[0] = 'V'; //perfectly legal and will update the value
I_RO_VALUE = new char[]{'V'}; //will cause compiler error
}
}
string
可以用作常量之外,还有其他引用类型吗?
const
使用除字符串以外的其他引用类型,但常量只能具有value null
。
这说明了这一点。简介:const必须在声明时初始化,只读可以在构造函数上初始化(因此,根据所使用的构造函数的不同,其值也不同)。
编辑:请参阅上面的Gishu的陷阱以获得微妙的区别
常量成员是在编译时定义的,不能在运行时更改。常量使用const
关键字声明为字段,并且必须在声明时进行初始化。
public class MyClass
{
public const double PI1 = 3.14159;
}
甲readonly
构件是一样的,因为它代表了一个不变的值的常数。区别在于readonly
成员可以在运行时在构造函数中初始化,也可以在声明成员时初始化。
public class MyClass1
{
public readonly double PI2 = 3.14159;
//or
public readonly double PI3;
public MyClass2()
{
PI3 = 3.14159;
}
}
const
static
(它们是隐式静态的)只读
static const int i = 0;
const
不能在方法内部进行声明吗?
const是编译时常量,而readonly允许在运行时计算值并在构造函数或字段初始化程序中设置。因此,“ const”始终是常数,但是“ readonly”在分配后是只读的。
C#小组的Eric Lippert拥有有关不同类型不变性的更多信息
只读:可以在运行时通过Ctor更改值。但不是通过成员函数
常量:通过消除静态。不能在任何地方(Ctor,Function,运行时等,无处)更改值
还有一个陷阱:只读值可以通过反射的“欺骗”代码来更改。
var fi = this.GetType()
.BaseType
.GetField("_someField",
BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(this, 1);
我相信const
所有对象的值都是相同的(并且必须使用文字表达式进行初始化),而readonly
每个实例的值都可以不同...
我们办公室的一位团队成员就何时使用const,static和readonly提供了以下指导:
最后一点:const字段是静态的,但反之则不正确。
它们都是常量,但是在编译时也可以使用const。这意味着差异的一方面是您可以将const变量用作属性构造函数的输入,但不能使用只读变量。
例:
public static class Text {
public const string ConstDescription = "This can be used.";
public readonly static string ReadonlyDescription = "Cannot be used.";
}
public class Foo
{
[Description(Text.ConstDescription)]
public int BarThatBuilds {
{ get; set; }
}
[Description(Text.ReadOnlyDescription)]
public int BarThatDoesNotBuild {
{ get; set; }
}
}
何时使用const
或readonly
const
readonly
App.config
,但一旦初始化,就无法更改另一个陷阱。
由于const实际上仅适用于基本数据类型,因此,如果要使用类,则可能会感到“被迫”使用ReadOnly。但是,请当心陷阱!ReadOnly表示您不能用另一个对象替换该对象(您不能使其引用另一个对象)。但是任何引用该对象的进程都可以自由修改该对象内部的值!
因此,不要混淆以为ReadOnly意味着用户不能更改任何东西。C#中没有简单的语法来防止类的实例更改其内部值(据我所知)。
C#.Net中的const和readonly字段之间存在显着差异
const默认情况下是静态的,需要使用常量值进行初始化,以后将无法对其进行修改。构造函数中也不允许更改值。并非所有数据类型都可以使用它。对于exDateTime。不能与DateTime数据类型一起使用。
public const DateTime dt = DateTime.Today; //throws compilation error
public const string Name = string.Empty; //throws compilation error
public readonly string Name = string.Empty; //No error, legal
readonly可以声明为静态的,但不是必需的。声明时无需初始化。可以使用构造函数来分配或更改其值。因此,当用作实例类成员时,它具有优势。两种不同的实例可能具有不同的只读字段值。对于前-
class A
{
public readonly int Id;
public A(int i)
{
Id = i;
}
}
然后可以使用即时特定值初始化readonly字段,如下所示:
A objOne = new A(5);
A objTwo = new A(10);
在这里,实例objOne的readonly字段值为5,而objTwo的值为10。使用const不可能。
常量将作为文字值编译到使用者中,而静态字符串将用作对所定义值的引用。
作为练习,尝试创建一个外部库并在控制台应用程序中使用它,然后更改该库中的值并重新编译(不重新编译使用者程序),将DLL放到目录中并手动运行EXE,您应该找到常量字符串不变。
常量和只读是相似的,但是它们并不完全相同。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 = r;
green = g;
blue = 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 = r;
green = g;
blue = 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修饰符仅防止您为该字段分配新引用。具体来说,它不会使引用指向的对象不可变。
有关详细信息,请参阅有关此主题的C#常见问题解答:http : //blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx
常量变量在编译时声明和初始化。病房之后不能更改该值。只读变量将仅从类的静态构造函数中初始化。只读仅在我们要在运行时分配值时使用。