15 使用属性以访问字段

1.什么是属性

定义:是字段和方法的交集—— 看起来像字段,用起来像方法。

访问属性所用的语法和访问字段一样。然而,编译器会将这种字段风格的语法自动转换成对特定访问器的调用。

访问器:取值和献值方法统称为访问器方法。两个方法有时也称为get访问器和set访问器,或者getter 和setter。

属性的声明如下所示:

AccessModifier Type ProperName
{

    get
    {
        //取值代码
    }

    set
    {
        //赋值代码
    }

}

属性可以包含两个代码块,分别以get和set关键字开头。其中,get 块包含读取属性时执行的语句,set块包含在向属性写入时执行的语句。属性的类型指定了由get和set访问器读取和写入的数据的类型。

 

属性和字段名称的注意事项:

例如一下代码,它实现了名为Employee的类。EmployeeID 属性提供对私有字段employeeID字段的公共访问,

class Employee
{

    private int employeeID;
    public int EmployeeID
    {

        get { return this. EmployeeID; }
        set { this. EmployeeID = value; }

    }

}

代码编译没有问题,但每次访问EmployeeID属性都会抛出StackoverflowException异常,这是由于get和set访问器不小心引用属性(以大写字母E开头)而不是私有字段(小写e),这造成了无限递归,最终造成可用内存被耗尽。这种bug是很难发现的!有鉴于此,我们以下划线开头命名为属性提供数据的私有字段。这样可以更加明显地和属性进行区分。除此之外的其他所有私有字段还是使用不以下划线开头的camelCase 标识符。

 

1.1使用属性

在表达式中使用属性时,要么从中取值,要么向其赋值。下例从ScreenPosition结构的X和Y属性中取值:

ScreenPosition origin=new ScreenPosition(e=0, 0);
int xpos =origin.x; // 实际调用origin.X. get
int ypos=origin.Y; // 实际调用origin.Y.get

注意,现在属性和字段是用相同的语法来访问。从属性取值时,编译器自动将字段风格的代码转换成对属性的get访问器的调用。类似地,向属性赋值时,编译器自动将字段风格的代码转换成对该属性的set访问器的调用:

origin.X=40;//实际调用origin.X.set. value 设为40
origin.Y=100; //实际调用origin.Y.set, value 设为100

如前所述,要赋的新值通过value变量传给set访问器。“ 运行时”自动完成传值。

 

还可同时对属性进行取值和赋值。在这种情况下,get和set访问器都会被用到。例如,编译器自动将以下语句转换成对get和set访问器的调用:

origin.X +=10;

提示:可采取和声明静态字段及方法一样的方式声 明静态属性。访问静态属性时,要附加类或结构名称作为前缀,而不是附加类或结构的实例名称作为前缀。

 

1.2只读属性

可以声明只包含get 访问器的属性,这称为只读属性。例如,以下代码将ScreenPosition结构的X属性声明为只读属性:

struct ScreenPosition
{

    private int. x;
    public int X
    {
        get { return this. X; }
    }

}

X属性不含set访问器,向X写入会报告编译时错误,例如:

origin.x =140; //编译时错误

1.3只写属性

类似地,可声明只包含set 访问器的属性,这称为只写属性。例如,以下代码将ScreenPosition结构的x属性声明为只写属性:

struct ScreenPosition
{

    private int. x;
    ...
    public int X
    {
        set { this. x = rangeCheckedX(value); }
    }

}

X属性不包含get访问器。所以,读取X会报告编译时错误,例如:

Console.WriteLine(origin.X);//编译时错误
origin.X = 200; //编译通过
origin.X += 18;//编译时错误

注意:只写属性适合对密码这样的数据进行保护。理想情况下,实现了安全性的应用程

序允许设置密码,但不允许读取密码。登录时用户要提供密码。登录方法将用户提供的密码与存储的密码比较,只返回两者是否匹配的消息。

 

1.4属性的可访问性

声明属性时要指定可访问性(public, private 或protected)。但在属性声明中,可为get和set访问器单独指定可访问性,从而覆盖属性的可访问性。例如,下面这个版本的ScreenPosition结构将x和Y属性的set访问器定义成私有,而get访问器仍为公共(因为属性是公共的):

struct ScreenPosition
{

    private int _x, _y;
    …
    public int X
    {

        get { return this._x; }
        private set { this._x=rangeCheckedX(value); }

    }

    public int Y
    {

        get { return this._y; }
        private set { this._y=rangeCheckedY(value); }

    }
    …

}

为两个访问器定义不同的可访问性时,必须遵守以下规则。

(1)只能改变 一个访问器的可访问性。例如,将属性声明为公共,但将它的两个访问器都声明成私有是没有意义的。

(2)访问器 的访问修饰符(也就是public, private或者protected)所指定的可访问性在限制程度上必须大于属性的可访问性。例如,将属性声明为私有,就不能将get访问器声明为公共(相反,应该属性公共,set访问器私有)。

 

2.理解属性的局限性

属性在外观、 行为和感觉上都像字段。但属性本质上是方法而不是字段。另外,属性存在以下限制。

(1)只有在结构或类初始化好之后,才能通过该结构或类的属性来赋值。下例的代码非法,因为结构变量location尚未使用new来初始化:

ScreenPosition location;
location.X = 40; //编译时错误,location 尚未赋值

(2)不能将属性作为ref或out参数值传给方法:但可写的字段能作为ref或out参数值传递。这是由于属性并不真正指向一个内存位置:相反,它指向的是一个访问器方法,例如:

MyMethod(ref location.X); // 编译时错误

(3)属性最多只能包含一个get和一个set访问器。不能包含其他方法、字段或属性。

(4)get和set访问器不能获取任何参数。要赋的值会通过内建的、隐藏的value变量自动传给set访问器。

(5)不能声明const 属性,例如:

const int X{ get { ... }set { ...} } //编译时错误

 

3.在接口中声明属性

接口除了能定义方法,还能定义属性。

例如:

interface IScreenPosition
{

    int X{get;set;}
    int Y{get;set;};

}

实现该接口的任何类或结构都必须实现X和Y属性,并在属性中定义get和set访问器,例如:

class ScreenPositlon : IScreenPosition
{

    public int X
    {
        get{...}
        set{...}
    }

    public int Y
    {
        get{...}
        set{…}
    }
    …

}

用途:例如可以用属性替代方法

 

4.生成自动属性

C#语言的设计者知道程序员都是“大忙人”,不该花时间写多余的代码。所以,C#编译器现在能自动为属性生成代码,如下所示:

class Circle
{

    public int Radius{ get; set; }
    …

}

在这个例子中,Circle 类包含名为Radius的属性。除了属性的类型,不必指定这个属性是如何工作的一get 和set访问器都是空白的。C#编译器自动将这个定义转换成私有字段以及一个默认的实现,如下所示:

class Circle
{

    private int _radius;
    public int Radius{
        get
        {

            return this._ radius;

        }

        set
        {

            this._radius = value;

        }

    }

    …

}

所以,只需写很少的代码就能实现简单属性。以后如果添加了额外的逻辑,也不会干扰现有的任何应用程序。

 

参考书籍:《Visual C#从入门到精通》

发布了46 篇原创文章 · 获赞 53 · 访问量 3707

猜你喜欢

转载自blog.csdn.net/qq_38992372/article/details/105018233
15