`
cdragon
  • 浏览: 76983 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

effective hierarchy(一)之 属性与索引器

阅读更多

编程笺言:“优良的设计不仅对使用过程隐去细节,也不允许数据成员被直接地访问。”

 

这一节,我们就看看索引器是如何将数组虚拟化了的......

 

一、属性

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]"的简洁形式。换句话说,一种语法上封装!

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics