常量、字段和成员属性
常量、字段和成员属性都是类的成员,用于维护类的内容或状态。通常,常量用于从不改变的值;字段用于维护类中的私有数据;成员属性用于控制对类中数据的访问。
常量
C#
使用const来声明有固定值(不可改变)的变量。
-
可在一条语句中使用关键字const声明多个常量。
-
常量必须定义为基本类型。
-
不能从类实例访问常量。
关于常量,最重要的是,要清楚它的值是在编译时确定的,这一点影响很大,改变常量值需要从新编译DLL,因为const的值是在编译的时候计算的。通常把一组常量存储在一个特殊的工具或辅助类中。要将这些常量声明为public,以便所有类都能访问。由于不需要创建类实例,所以将类声明为abstract。
字段
字段也用于在类中存储数据。同const相比,主要有两个不同:它的值在运行时确定,另外类型也不仅限于基本类型。
字段修饰符
除访问修饰符外,字段还有另外两个修饰符:static和readonly。
修饰符
|
定义
|
static
|
静态字段是类的状态,而不是类实例的状态。这说明,可以指定classname,fieldname来直接访问字段,而无需创建类实例。从这个角度上讲,静态字段有点类似于常量。
|
readonly
|
只读字段只能在声明语句或类结构构造函数中赋值。其效果实际上是将字段变成了一个常量。如果以后代码想要改变字段的值,就会导致错误。
|
对此有一条经验,字段应该定义为pirvate,以保证对象的状态是安全的,外部无法处理。然后根据外部访问的需要,再使用方法和成员属性来获取设置这些私有数据。
如果没有初始化字段,则会将其设置为相应类型的默认值:数值的默认值为0,引用类型的值为null,字符串的值默认为单引号(
’’
),布尔值默认为false。
有一种情况下将字段设置为public是有意义的:即程序需要一个全局常量时。通过声明字段为public static readonly,可以创建一个运行时常量。
成员属性
成员属性(Property)用于控制对类中值的读写访问。Java和C++程序创建成员属性时,需要编写一个存取方法(accessor)来获取字段数据,并编写一个修改方法(mutator)设置字段。与这些语言不同,事实上,C#编译器可以识别一种特殊的成员属性构造,并创建和访问数据提供了一种简化的语法。确切的说,这个语法与相应的C++并没有什么天壤之别,但它确实能使编译器产生更高的执行代码。
语法:
[attribute]
<
modifier
>
<
data type
>
<
property name
>
{
[access modifier]
get
{
return
(PropertyValue)
}
[access modifier]
set
{ Code to
set
a field to the keyword value}
}
注意:
-
除了4中访问修饰符外,成员属性修饰符可以是static、adstract、new、virtual或override。abstract只用在抽象类中;virtual用在基类中,并且允许子类覆盖该成员属性。
-
value
是一个隐式的参数,其中包含调用成员属性时传递的值。
-
get
和set存取方法(获取方法和设置方法)可以有不同的访问修饰符。
创建和访问成员属性
public
class
Upholstery
{
private
double
YardPrice;
public
double
PricePerYard
{
get
{
return
YardPrice; }
set
{
if
(value
<=
0
)
throw
new
ArgumentOutOfRangeException(
"
Price must be greater than 0.
"
);
YardPrice
=
value;
}
}
}
代码中的get块相当于传统的存取方法,而set相当于修改方法。包含其中的一个就可以,如果没有get块,成员属性就是只写的,如果没有set块的话,成员属性则为只读。
get
块中所有的return语句必须指定一个表达式,而且它能隐式的转换成成员属性的类型。
使用成员属性的效率不一定比直接使用字段的效率低。对于仅包含少量代码的非虚(non-virtual)成员属性类说,JIT编译器可能会用get或set块中的实际代码取代对存取方法的调用。这个过程称为(inlining),可以减少运行时的调用开销。其结果是这些代码与使用字段的代码同样高效,而且灵活的多。
索引器
索引器(indexer)常常称为参数化成员属性。就像成员属性一样,它在类中声明,实体中可以包含获取和设置方法,这些存取方法与成员属性存取方法的语法相同,但索引器与成员属性有两点不同:它可以接受一个或多个参数,而且使用关键子this作为索引器的名字。其完整语法为:
[attribute]
<
modifier
>
<
return
type
>
this
[property(s)]
例子:
class
IndexerClass
{
private
int
[] arr
=
new
int
[
100
];
public
int
this
[
int
index]
//
Indexer declaration
{
get
{
if
(index
<
0
||
index
>=
100
){
return
0
;}
else
{
return
arr[index]; }
}
set
{
if
(
!
(index
<
0
||
index
>=
100
))
{arr[index]
=
value; }
}
}
}
class
MainClass
{
static
void
Main()
{
IndexerClass test
=
new
IndexerClass();
test[
3
]
=
256
;
test[
5
]
=
1024
;
for
(
int
i
=
0
; i
<=
10
; i
++
)
{
System.Console.WriteLine(
"
Element #{0} = {1}
"
, i, test[i]);
}
}
}
输出:
Element #0 = 0
Element #1 = 0
Element #2 = 0
Element #3 = 256
Element #4 = 0
Element #5 = 1024
Element #6 = 0
Element #7 = 0
Element #8 = 0
Element #9 = 0
Element #10 = 0
注意:
索引器不支持static修饰符,因为索引器只适用于实例。
索引器的优点在于,它对客户隐藏了数组操作细节,而且在返回值之前,可以完成有效性检查或数据修改。如果对象的成员属性可以表示为集合(而不是标量值),这种情况下索引器最为适用。