聚拓互联

http://www.ejutuo.com
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

<四> 属性与索引器

   属性(property)是类、结构和接口的命名成员,它们提供了通过访问器(set和get)读、写或计算私有字段的灵活机制。它是字段的自然扩展,都是与类型相关的有名称的成员,并且访问字段和属性的语法是相同的。所不同的是属性不指明存储位置,而是使用访问器读、写和计算求值。

 

1、属性的定义

   [访问修饰符] 类型 成员名

   {

     get //读访问器

     {

        //语句块

      }

     set //写访问器

     {

        //语句块

      }

    }

访问修饰符:可使用的修饰符,包括new、static、virtual、abstract、override和四种访问修饰(public、protected、private、internal)的合法组合。

 类型:属性的类型。

 标识符:属性名称。

 get: 通过return读取属性的值,它的返回类型与属性的类型相同。只带有get访问器的属性称为只读属性,表明属性的值只能读不能改写。

 set: 通过value设置属性的值,value的类型与属性的类型相同。只带有set访问器的属性称为只写属性,表明属性的值只能设置而不能读出。

 

下面的例子将说明如何使用属性:

using System;

using System.Collections;

namespace 笔记

{

    class Address

    {

        //定义字段变量

        protected string City;

        protected string ZipCode;

 

        //定义属性

        public string ProCity

        {

            get { return City; }      //City是之前已经定义好的"字段变量"

            set { City = value; }

        }

        public string ProZipCode

        {

            get { return ZipCode; }

            set { ZipCode = value; }   //ZipCode是之前已经定义好的"字段变量"

        }

    }

    class PropertyApp

    {

        public static void MMain()

        {

            Address addr = new Address();              //创建类对象

            addr.ProCity = "广东科学技术职业学院";     //设置属性的值

            string MyCity = addr.ProCity;              //读取属性的值

            Console.WriteLine("MyCity:{0}", MyCity);

            addr.ProZipCode="13824128413";             //设置属性的值

            string MyZipCode = addr.ProZipCode;        //读取属性的值

            Console.WriteLine("MyZipCode:{0}", MyZipCode);

        }

    }

}

程序运行结果:

MyCity:广东科学技术职业学院

MyZipCode:13824128413

 

2、静态属性

   如果在定义属性时使用了关键字,则该属性就是一个静态属性。

   静态属性有以下特点:

   ◆ 与其他静态成员一样,静态属性不与特定实例相关联,它属性整个类,并且不能通过实例引用。相反,它与类型相关联,并且只能通过类型名称引用。例如,在下列语句中:

   Button NewBut=new Button();

   string s=NewBut.Caption;

Caption属性与NewBut实例相关联,如果将Caption声明为静态属性,必须转而使用Button类名:

   string s=Button.Caption;

   ◆ 定义静态属性时,不能同时出现virtual、abstract或override修饰符。

   ◆ 在实例属性的访问器中可以用this来访问类的实例,但在静态属性的访问器中使用this是非法的。

   下面程序演示静态属性的使用

using System;

using System.Collections;

namespace 笔记

{

    public class Employee

    {

        public static int EmpNum;

        private static int Counter;

        private string Name;

 

        //一个读写实例属性

        public string ProName

        {

            get { return Name; }

            set { Name = value; }

        }

 

        //一个只读静态属性

        public static int ProCounter

        {

            get { return Counter; }

        }

 

        //构造函数

        public Employee()

        {

            //计算职员的数量

            Counter = ++Counter + EmpNum;

        }

    }

    public class MainClass

    {

        public static void MMain()

        {

            Employee.EmpNum = 100;   //静态字段变量的调用

            Employee NewEmp = new Employee();

            NewEmp.ProName = "刘伟梅";

            Console.WriteLine("职员号:{0}", Employee.ProCounter); //静态属性的调用

            Console.WriteLine("职员名:{0}", NewEmp.ProName);

        }

    }

}

 

程序运行结果:

职员号:101

职员名:刘伟梅

 

3、索引器

   索引器(indexer)是C#引入的一个新的类成员,是C#特有的特性。使用索引器的目的是为了能够像数组一样访问类中的数组型的对象。通过对对象元素的下标进行索引,就可以访问指定的对象。索引器类似于属性,也是使用get关键字和set关键字定义了对被索引元素的读写权限,它们之间主要有两个不同之处:第一,索引器有索引参数;第二,由于类本身被用作一个数组,因而this关键字被用做索引器的名称(实际上使用的是对象的名称)。

 (1)索引器的定义

   [属性][索引器修饰符] 类型 this[形式参数表]

   {

     get

    { return ?; //返回所需要的数据 }

     set

     { ?=value;   //设置所需要的数据 }

    }

索引器修饰符为以下之一new、public、protected、internal、private、virtual、sealed、override、abstract、extern。关于有效的修饰符组合,索引器声明与方法声明遵循相同的规则(除了不允许在索引器声明中使用static修饰符以外)。

◆ 索引器声明的类型指定由该声明引入的索引器的元素类型。除非索引器是显式接口成员实现,否则类型要后跟关键字this。对于显式接口成员实现,类型后跟一个接口类型、一个“.”和关键字this。与其他成员不同,索引器不具有用户定义的名称。

◆ 形参表指定索引器的参数。索引器的形参表对应于方法的形参表,不同之处在于至少必须指定一个参数,并且不允许使用ref和out参数修饰符(因为索引器元素并不属于变量。因此不可能将索引器元素作为ref或out参数传递)。

◆ 同一个类中的索引器签名必须不同。索引器的形参表定义索引器的签名。具体说来,索引器的签名由其形参的数量类型组成。形参的元素类型和名称(它们都是this)不是索引器签名的组成部分。

索引器和属性在概念上非常类似,主要区别体现在以下几个方面:

   ◆ 属性通过它的名称来标识,而索引器由它的签名标识。

   ◆ 属性是通过简单名称或成员访问(类型.名称的形式)来访问的,而索引器元素则是通过元素访问方式来访问的。

   ◆ 属性可以是静态成员,而索引器始终是实例成员。

   ◆ 属性的get访问函数对应不带参数的方法,而索引器get访问函数对应与索引器具有相同的形参表的方法。

   ◆ 属性的set访问函数对应于具有名为value的单个参数的方法,而索引器的set访问函数对应于与索引器具有相同的形参表加上一个名为value的附加参数的方法。

   ◆ 索引器访问函数使用与索引器参数相同的名称声明局部变量导致编译时错误。

   ◆ 在重写属性声明中,继承属性是使用语法base.P访问的,其中P为属性名称。在重写索引器声明中,继承索引器是使用语法base[E]访问的,其中E是一个用逗号分隔的表达式列表。

 (2)调用索引器

   定义索引器后,就可以像访问数组元素一样访问对象了。

例1:下面程序演示了如何使用索引器

 

using System;

using System.Collections;

namespace 笔记

{

    class MyClass

    {

        private string[] data = new string[5];

       

        //索引器定义,根据下标访问data

        public string this[int index]

        {

            get

            {

                return data[index];

            }

            set

            {

                data[index] = value;

            }

        }

    }

    class MyClient

    {

        public static void MMain()

        {

            MyClass NewMyClass = new MyClass();

           

            //调用索引器set赋值

            NewMyClass[0] = "刘伟梅";

            NewMyClass[1] = "女";

            NewMyClass[2] = "20";

            NewMyClass[3] = "广东省高州镇江";

            NewMyClass[4] = "我的好同学";

 

            //调用索引器get读出

            Console.WriteLine("{0},{1},{2},{3},{4}", NewMyClass[0], NewMyClass[1], NewMyClass[2], NewMyClass[3], NewMyClass[4]);

        }

    }

}

程序运行结果:刘伟梅,女,20,广东省高州镇江,我的好同学

 

索引器的get和set中可以增加各种计算和控制代码

例2:包含计算和控制代码的索引器

using System;

using System.Collections;

namespace 笔记

{

    public class SpellingList

    {

        static public int size = 10;

        protected string[] words = new string[size];

        public SpellingList()

        {

            for (int x = 0; x < size; x++)

                words[x] = string.Format("Word{0}", x);

 

        }

        //索引器,根据下标访问words

        public string this[int index]

        {

            get

            {

                string tmp;

                if (index >= 0 && index <= size - 1)

                    tmp = words[index];

                else

                    tmp = "";

                return (tmp);

            }

            set

            {

                if (index >= 0 && index <= size - 1)

                    words[index] = value;

            }

        }

    }

    public class TestApp

    {

        public static void MMain()

        {

            SpellingList myList = new SpellingList();

            myList[3] = "=====";

            myList[4] = "刘伟梅";

            myList[5] = "是";

            myList[6] = "我的好同学";

            myList[7] = "=====";

            for (int x = 0; x < SpellingList.size; x++)

                Console.WriteLine(myList[x]);

        }

    }

}

程序运行结果:

=====

刘伟梅

我的好同学

=====

(3)索引器重载

   若同一类中包含多个索引器,因为它们有着同样的名字(this),所以不同签名的索引器组成了重载索引器。

   C#编译器选择重载索引器的的原则与常规重载方法一样,在这里不再赘述。