浅析C#中的const与readonly异同
以前只是用const与readonly声明常量,今天在网上看了它们的一些其它属性,觉得有必要弄清楚它们的用法与异同,所以动手找了找,也写了几行代码以呈现,还望大家给予指点。
先贴代码。
定义一个简单类,声明两个公开变量,_const,_readonly.
{
public const string _const;
public readonly string _readonly;
}
此时会编译会出现错误:
错误 1 常量字段要求提供一个值 (在_const行)。则表明,const变量在声明是就要赋值,而readonly则不一定。
那好,我们就对这两个变量赋值
{
public const string _const = "const";
public readonly string _readonly;
}
然后,在程序中调用此两个变量,
{
static void Main(string[] args)
{
ConstReadonly cr = new ConstReadonly();
Console.WriteLine(cr._readonly);
Console.WriteLine(cr._const);
}
}
此时,编译不通过,查看错误
无法使用实例引用访问静态成员“ConstReadonly._const”;改用类型名来限定它。
原来const声明的变量,其为static变量,而readonly则不是。
把cr._const更改为:ConstReadonly._const。
{
static void Main(string[] args)
{
ConstReadonly cr = new ConstReadonly();
Console.WriteLine(cr._readonly);
Console.WriteLine(ConstReadonly._const);//_const为静态变量
}
}
编译通过,输出结果为:
const
可见,可能不用给_readonly赋初始值。当然,这只是可不可以的讨论,至于实际编程中,要自己把握了。此处,本人查的资料显示为,const编译时赋值,如果没有赋值,则编译不通过;readonly则是在程序运行时赋值,那么它可以同.NET自己值初始null。
下面看一看,给他们赋值变量会出现什么问题。
{
public string _str = "str";
public const string _const = _str;
public readonly string _readonly = _str;
}
编译,出现错误:
错误 1 非静态的字段、方法或属性“ConstReadonly._str”要求对象引。
其实,从前面就可以了解到,既然const是静态类型,则只能使用静态字段,方法,属性赋值。此处的ConstReadonly._str则不是静态的。
错误 2 “ConstReadonly._const”的类型为“string”。只能用 null 对引用类型(字符串除外)的常量进行初始化
不说此处,先看下面。
更改之后,
{
public string _str = "str";
public static string _sstr="sstr";
public const string _const = "const";
public readonly string _readonly = _str;
}
编译,又出现错误:
错误 1 字段初始值设定项无法引用非静态字段、方法或属性。
看来readonly也要引用静态的字段,方法或属性。
但是,它没有上面的错误2
在这里,我们可以想一下,const常量是编译时赋值,readonly是运行时赋值。无论是非静态的,或是静态的属性,方法,字段都是在程序运行(或类第一次运行或实例化)的时候赋值,即,它仍然是运行时赋值,不是编译时赋值。既然如此,那么要对const常量赋值,用运行时才能确定的变量或常量,是行不通的。
但是,readonly是运行时赋值,可以用静态方法,属性,字段赋值。至于上面的错误,可以借用下c#语言规范:实例字段的变量初始值设定项不能引用正在创建的实例。因此,在变量初始值设定项中引用 this 是编译时错误,同样,在变量初始值设定项中通过 simple-name 引用任何一个实例成员也是一个编译时错误。上面的_str是一个实例变量,而_sstr则是一个静态变量,据此,可以知道,在readonly初始化时,可以把_sstr赋值给_readonly。
{
public string _str = "str";
public static string _sstr="sstr";
public const string _const = "const";
public readonly string _readonly=_sstr;
}
编译,运行,通过。运行结果。
sstr
const
对于readonly变量,还可以在构造函数中初始化。
{
public string _str = "str";
public static string _sstr="sstr";
public const string _const = "const";
public readonly string _readonly=_sstr;
public ConstReadonly()
{
_readonly = _str;
}
}
编译,运行,通过。结果
str
const
从已上可以看出,const与readonly区别,主要是因为,const为static类型,而readonly不是。所以,我们还可以定义static readonly类型的常量。
{
public string _str = "str";
public static string _sstr="sstr";
public const string _const;
public readonly string _readonly=_sstr;
public static readonly string _staticReadonly;
public ConstReadonly()
{
_readonly = _str;
}
static ConstReadonly()
{
_staticReadonly = "staticReadonly";
_const="_const";
}
}
此时,_staticReadonly = "staticReadonly";是正确的,它可以在静态构造函数中初始化。但是,_const="_const";则不行,原因是在定义_const时,就要进行定义。即使在定义时,_const赋了初始值,也不能在静态构造函数中再次赋值。
此外,除了值类型的常量,const对于引用类型,只能是null或字符串常量。而其它值则不行。但是readonly则不同,它可以是任何类型。并且,对于其代表的常量,不可以改变其引用常量,但是可以改变其引用常量中的,某些可以改变的属性等。
{
public const string _const="_const";
public readonly Person _readonly;
public ConstReadonly()
{
_readonly = new Person();
}
}
public class Person
{
public string name;
public Person()
{
this.name = "Untitled";
}
public Person(string name)
{
this.name = name;
}
}
上面定义了Person,有一个属性:name。
{
static void Main(string[] args)
{
ConstReadonly cr = new ConstReadonly();
Console.WriteLine(cr._readonly.name);
cr._readonly.name = "Changed";
Console.WriteLine(cr._readonly.name);
}
}
编译,运行,通过。输出结果为:
Untitled
Changed
。
以上是对const与readonly的简单分析,也是本人拙见,还望高手们不吝赐教,以求进步。
---------------------------------------------