本篇主要描述了C#中Property和Indexer的使用,在保证数据封装性和安全性的情况下,使得用户可以象field和array一样访问被封装的数据,提高程序的可读性。
- Properties允许你在保持class内field封装性的前提下使用public field-like语法访问;Property是介于logical field和physical method之间的功能,甚至可以脱离实际的field。
struct ScreenPosition
{
public ScreenPosition(int X, int Y)
{
this.x = rangeCheckedX(X);
this.y = rangeCheckedY(Y);
}
public int X
{
get { return this.x; }
set { this.x = rangeCheckedX(value); }
}
public int Y
{
get { return this.y; }
set { this.y = rangeCheckedY(value); }
}
private static int rangeCheckedX(int x) { ... }
private static int rangeCheckedY(int y) { ... }
private int x, y;
}
ScreenPosition origin = new ScreenPosition(0, 0);
int xpos = origin.X;
int ypos = origin.Y;
- 数值通过value变量传递到set访问符;可以定义static的property;可以定义只含有get访问符的只读property;可以定义只含有set访问符的只写property;get或set访问符可以具有不同的访问等级(只能设置启动的一个),但是都必须不高于property的整体访问等级。
- Property和实际的field相比也具有局限性:不能通过set访问符进行初始化;property不能作为ref/out参数;不能定义const的property。
- Interfaces中也可以描述property,在实现这个接口的class/struct中去实现这些访问符;如果你是通过class实现interface中的property,还可以将实现声明成virtual的。
interface IScreenPosition
{
int X { get; set; }
int Y { get; set; }
}
struct ScreenPosition : IScreenPosition
{
...
public int X
{
get { ... }
set { ... }
}
public int Y
{
get { ... }
set { ... }
}
...
}
class ScreenPosition : IScreenPosition
{
...
public virtual int X
{
get { ... }
set { ... }
}
public virtual int Y
{
get { ... }
set { ... }
}
...
}
- 如果你使用explicit interface implementation来实现property,这个实现就必须是non-public和non-virtual的。
struct ScreenPosition : IScreenPosition
{
...
int IScreenPosition.X
{
get { ... }
set { ... }
}
int IScreenPosition.Y
{
get { ... }
set { ... }
}
...
private int x, y;
}
- Property适用于访问单一数值的field,如果需要访问具有多个数值的field,就可以使用indexer;Indexer可以看作smart array,而property可以看做smart field;一个class/struct只能包含一个indexer;要访问的下标通过index变量传入。
struct IntBits
{
public IntBits(int initialBitValue)
{
bits = initialBitValue;
}
public bool this [ int index ]
{
get
{
return (bits & (1 << index)) != 0;
}
set
{
if (value) // Turn the bit on if value is true, otherwise turn it off
bits |= (1 << index);
else
bits &= ~(1 << index);
}
}
private int bits;
}
int adapted = 63;
IntBits bits = new IntBits(adapted);
bool peek = bits[6]; // retrieve bool at index 6
bits[0] = true; // set the bit at index 0 to true
bits[31] = false; // set the bit at index 31 to false
- 你可以定义static的Property,但是不能定义static的indexer,你可以定义只包含set或者get访问符的indexer。
- Indexer可以使用非数字的下标,Array只能适用整数下标;Indexer可以被重载,Array不能;Indexer不能作为ref/out参数,Array元素可以。
- 你可以在interface中声明indexer,让继承这个接口的class/struct来实现indexer;如果你是通过class实现interface中的indexer,还可以将实现声明成virtual的
interface IRawInt
{
bool this [ int index ] { get; set; }
}
struct RawInt : IRawInt
{
...
public bool this [ int index ]
{
get { ... }
set { ... }
}
...
}
class RawInt : IRawInt
{
...
public virtual bool this [ int index ]
{
get { ... }
set { ... }
}
...
}
- 如果你使用explicit interface implementation来实现indexer,这个实现就必须是non-public和non-virtual的。
struct RawInt : IRawInt
{
...
bool IRawInt.this [ int index ]
{
get { ... }
set { ... }
}
...
}
(待续,下一篇将描述C#中Delegate和Event的使用,说明C#中传递和处理事件的机制)