编程笺言:“优良的设计不仅对使用过程隐去细节,也不允许数据成员被直接地访问。”
这一节,我们就看看索引器是如何将数组虚拟化了的......
一、属性
1.基本
(1)属性是字段意义上的扩充,使通过相同的语法访问;但属性不是变量,不是设计用来作为存储定位(storage location)使用,不可能把属性作为ref或out方式的参数传递;
(2)属性的语法为
[attributes] [modifiers] type [interface-type.]identifier {accessor-declaration}
(3)属性综合了字段和函数的特性,对象使用者可以象使用字段一样地使用属性;而要实现属性,必须使用最少一个代码块,最多两个代码块,以表示get访问器与/或(and/or)set访问器;
(4)属性数据的实际储存以“回存”(backing store)的方式进行,回存一般使用私有字段--以保证字段的属性,这一唯一的访问途径;
(5)属性有用于计算的读、写值的访问器(accessor);
(6)属性可以声明在接口上,称为接口属性;接口属性的访问器中不具有体,只需使用get;和set;关键字标明--该属性是否为读写、只读或只写即可;
(7)属性又叫无参属性,它是有参属性的变形,默认的参数是value值;
(8)属性有多项用途:
a/在允许变化之前,进行数据检验;
b/透明地公开类的数据,这些数据实际上是从其它的数据源如数据库检索而来的;
c/当更改数据时,采取对应措施,如激发某个事件或改变其它字段的值;
2.属性修饰符
(1)可使用四种访问修改器,public、private、protected、internal或protected internal;
(2)同一个属性的get、set访问器可以使用不同的修改器;
(3)静态(访问)的属性,表示该属性在任何时候都可访问;
(4)虚的属性,从派生类中--用override关键字重写属性行为,也可用sealed关键字来覆写;
(5)抽象的属性,不在该类中实现,但派生类必须实现;
(6)静态的属性,它的get、set访问器中不能使用virtual、abstract或override修饰符,否则会引起错误;
3.get访问器
(1)get访问器的主体类似于方法的格式;
(2)它必须返回属性声明的类型的值;
(3)它的执行等效于读取字段的值;例如,当从get访问器返回私有变量且能够进行优化(optimization are enabled)时,编译器负责内联(inline)调用get访问器的方法,但虚(virtual)get访问器方法除外,大体是编译器于编译时并不确定哪个方法会在运行时被调用。
(4)get访问器必须由return或throw语句中止,控制权不能转出到访问器主体之外;
(5)不建议使用get访问器来更改对象的状态(state of object),其本意是设计作返回字段值或计算且返回值使用;
//参考示例
class Employee
{
private string name;
public string Name
{
get
{
return name != null ? name : "NA";
}
}
}
4.set访问器
(1)set访问器类似于无返回值(void)的方法;
(2)使用隐式参数value,value的类型与属性的类型相同;
(3)为属性赋值时,set访问器和带着新值的参数一起被调用;
(4)为set访问器的本地变量不能使用隐式参数名value,否则会引起错误;
//主要用途示例
public class Employee
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
public class Manager : Employee
{
private string name;
// Notice the use of the new modifier:
public new string Name
{
get { return name; }
set { name = value + ", Manager"; }
}
}
class TestHiding
{
static void Main()
{
Manager m1 = new Manager();
// Derived class property.
m1.Name = "John";
// Base class property.
((Employee)m1).Name = "Mary";
System.Console.WriteLine("Name in the derived class is: {0}", m1.Name);
System.Console.WriteLine("Name in the base class is: {0}", ((Employee)m1).Name);
}
}
/* Output
Name in the derived class is: John, Manager
Name in the base class is: Mary
*/
//interface 属性示例
interface IEmployee
{
string Name
{
get;
set;
}
int Counter
{
get;
}
}
public class Employee : IEmployee
{
public static int numberOfEmployees;
private string name;
public string Name // read-write instance property
{
get
{
return name;
}
set
{
name = value;
}
}
private int counter;
public int Counter // read-only instance property
{
get
{
return counter;
}
}
public Employee() // constructor
{
counter = ++counter + numberOfEmployees;
}
}
class TestEmployee
{
static void Main()
{
System.Console.Write("Enter number of employees: ");
Employee.numberOfEmployees = int.Parse(System.Console.ReadLine());
Employee e1 = new Employee();
System.Console.Write("Enter the name of the new employee: ");
e1.Name = System.Console.ReadLine();
System.Console.WriteLine("The employee information:");
System.Console.WriteLine("Employee number: {0}", e1.Counter);
System.Console.WriteLine("Employee name: {0}", e1.Name);
}
}
二、索引器(有参属性)
1.基本
(1)索引器提供了语法便利性,以便客户端程序能象数组一样地访问类、结构或接口的实例(请问,数组索引的是什么?答,数组元素;索引器索引的是什么?答,实例中的元素);
(2)索引器多用于以下这些类型中的实现:主要用于封装内部集合或数组的类型;
举例,一个名为TempRecord的类,记录24小时内10个时间的温度记录,浮点型数组"temps”记录温度,DateTime型数组保存了日期。在该类中实现索引器,以使客户端用--float temp = tr[4],而不是float temp = tr.temps[4]--来访问TempRecord实例中的温度。
(3)索引器符号使客户端程序的语法得到简化,同时使开发者更容易理解类的设计用途;
(4)索引器的语法为:
[attributes] [modifiers] type [interface-type.]this [formal-index-parameter-list] {accessor-declarations}
(5)索引器类型和它的参数类型,必须像索引器本身一样可访问;
(6)索引器签名是由形参的个数和类型组成,不包括(include)索引器类型或形参的名字;在一个类中声明的多个索引器,它扪的签名不能相同;
(7)索引器值不属于(classfied)变量,因此,不可能传递索引器值作为ref或out参数;
(8)要提供其它语言可以使用的索引器的名字,在声明中要使用name特性(attribute),如
//TheItem是索引器名字;不提供索引器名字,则缺省为Item
[System.Runtime.CompilerServices.IndexerName("TheItem")]
// Indexer declaration
public int this [int index]
{
}
(9)索引器的索引类型不限于整数,可以使用其它如字符串等类型;使用字符串时,通过在集合中搜索来取得对应值;
2.建议采纳的编程风格:
(1)适当地增加错误处理,以避免客户端程序传递进来非法索引值;
(2)尽可能严格地限制get和set访问器的可访问性(accessibility),尤其是对set访问器。
3.接口中的索引器
(1)索引器可在接口上声明;它的语法为:
[attributes] [new] type this [formal-index-parameter-list] {interface-accessors}
(2)接口中索引器的访问器与类中索引器的访问器不同,表现为a/不使用修饰符 b/没有体;所以访问器的目的仅是用于指示读写、只读还是只写;
public interface ISomeInterface
{
//...
// Indexer declaration:
string this[int index]
{
get;
set;
}
}
(3)同一接口中,索引器的签名不能相同;
//主要用途示例:索引器示例,通过该例可以清楚地看到索引器实现对集合或数组的操作
//故,在编译器内联后,索引器最终能够提供语法上的便利性
class TempRecord
{
// Array of temperature values
private float[] temps = new float[10] { 56.2F, 56.7F, 56.5F, 56.9F, 58.8F,
61.3F, 65.9F, 62.1F, 59.2F, 57.5F };
// To enable client code to validate input when accessing your indexer.
public int Length
{
get { return temps.Length; }
}
// Indexer declaration.
// If index is out of range, the temps array will throw the exception.
public float this[int index]
{
get
{
return temps[index];
}
set
{
temps[index] = value;
}
}
}
class MainClass
{
static void Main()
{
TempRecord tempRecord = new TempRecord();
// Use the indexer's set accessor
tempRecord[3] = 58.3F;
tempRecord[5] = 60.1F;
// Use the indexer's get accessor
for (int i = 0; i < 10; i++)
{
System.Console.WriteLine("Element #{0} = {1}", i, tempRecord[i]);
}
// Keep the console window open in debug mode.
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
}
/* Output:
Element #0 = 56.2
Element #1 = 56.7
Element #2 = 56.5
Element #3 = 58.3
Element #4 = 58.8
Element #5 = 60.1
Element #6 = 65.9
Element #7 = 62.1
Element #8 = 59.2
Element #9 = 57.5
*/
//主要用途示例:接口上的索引器示例
// Indexer on an interface:
public interface ISomeInterface
{
// Indexer declaration:
int this[int index]
{
get;
set;
}
}
// Implementing the interface.
class IndexerClass : ISomeInterface
{
private int[] arr = new int[100];
public int this[int index] // indexer declaration
{
get
{
// The arr object will throw IndexOutOfRange exception.
return arr[index];
}
set
{
arr[index] = value;
}
}
}
class MainClass
{
static void Main()
{
IndexerClass test = new IndexerClass();
System.Random rand = new System.Random();
// Call the indexer to initialize its elements.
for (int i = 0; i < 10; i++)
{
test[i] = rand.Next();
}
for (int i = 0; i < 10; i++)
{
System.Console.WriteLine("Element #{0} = {1}", i, test[i]);
}
// Keep the console window open in debug mode.
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
}
/* Sample output:
Element #0 = 360877544
Element #1 = 327058047
Element #2 = 1913480832
Element #3 = 1519039937
Element #4 = 601472233
Element #5 = 323352310
Element #6 = 1422639981
Element #7 = 1797892494
Element #8 = 875761049
Element #9 = 393083859
*/
小结:
(1)属性和索引器具有相似的地方,后者被称做带参数的属性;但索引器常用于对集合或数组的封闭类,来进行访问语法的简化;
(2)它们都可以用在接口中;
(3)索引器,简言之,即对集合的实例中的数组进行操作时,可以用"实例[n]"的简洁形式。换句话说,一种语法上封装!
本文介绍了C#中属性和索引器的概念与用法。属性是字段的扩展,提供了读写字段值的能力,并允许在访问前进行数据验证。索引器则使类的实例能够像数组一样被索引,简化了集合或数组的访问语法。
1994

被折叠的 条评论
为什么被折叠?



