标签:
属性拥有两个类似于函数的块,一个块用于获取属性的值,另一个块用于设置属性的值。这两个块也称为访问器,分别用get和set关键字来定义,可以用于控制对属性的访问级别。可以忽略其中的一个块来创建只读或只写属性(忽略get块创建只写属性,忽略set块创建只读属性)。当然,这仅适用于外部代码,因为类中的其他代码可以访问的数据。还可以在访问器上包含可访问修饰符,例如使get块变成公共的,把set块变成保护的。只有包含其中一个一个块,才能获得有效属性(既不能读取也不能修改的属性没有任何用途)。
属性的基本结构包括标准的可访问修饰符(public、private等),后跟类名、属性和get块(或set块,或者get块和set块,其中包含属性处理代码)。
public int myIntProp
{
get
{
//Property get code.
}
set
{
//Property set code.
}
}
1 get关键字
get块必须有一个属性的返回值,简单的属性一般与私有字段相关联,以控制对这个字段的访问,此时get块可以直接返回该字段的值,例如:
private int myInt;
public int myIntProp
{
get
{
return myInt;
}
set
{
//Property set code.
}
}
类外部的代码不能直接访问这个myInt字段,私有的,必须使用属性来访问该字段。
2 set关键字
set函数以类似的方法把一个值赋给字段。这里使用value表示用户提供的属性值:
private int myInt;
public int myIntProp
{
get
{
return myInt;
}
set
{
myInt = value;
}
}
value等于类似与属性相同的值,所以如果属性和字段使用相同的类型,就不必担心数据类型转换了。
这个简单的属性只能直接访问myInt字段。在对操作进行更多的控制的时候,属性的真正作用才能发挥出来,例如,使用下面的代码实现set块:
set
{
if(value >= 0 && value <= 10)
myInt = value;
}
只用赋给属性的值在1~10之间,才会改myInt。此时,要做一个重要的设计选择:如果使用了无效值,该怎么办:
一般情况下,后面两个选择效果较好,选择哪个选项取决于如何使用类,以及给用户授予多少控制权。抛出异常给用户提供的控制权相当的大,例如:
set
{
if(value >= 0 && value <= 10)
myInt = value;
else
throw (new ArgumentOutOfRangeException("myIntProp",value,"myIntProp must be assigned a value between 0 and 10."))
}
这可以在使用属性的代码中通过try...catch...finaly逻辑来处理。
注:属性可以使用virtual、override和abstract关键字,就像方法一样,但这几个关键字不能用于字段。最后,如上述,访问器可以有自己的访问性。
实例:
public class MyClass
{
public readonly string Name;
private int intVal;
public int Val
{
get
{
return intVal;
}
set
{
if (value >= 0 && value <= 10 )
intVal = value;
else
throw (new ArgumentOutOfRangeException("Val",value,"Val must be assigned a value between 0 ang 10."));
}
}
public override string ToString()
{
return "Name:"+Name+"\nVal:"+Val;
}
private MyClass(): this("Default Name")
{
}
public MyClass(string newName)
{
Name = newName;
intVal = 0;
}
}
static void Main(string[] args)
{
Console.WriteLine("Creating object myobj...");
MyClass myObj = new MyClass("My Object");
Console.WriteLine("myObj created.");
for (int i = -1; i <= 0; i++ )
{
try
{
Console.WriteLine("\nAttempting to assign {0} to myObj.val...",i);
myObj.Val = i;
Console.WriteLine("Value {0} assigned to myObj.val.", myObj.Val);
}
catch(Exception e)
{
Console.WriteLine("Exception {0} throw.",e.GetType().FullName);
Console.WriteLine("Message:\n\"{0}\"",e.Message);
}
}
Console.WriteLine("\nOutputting myObj.ToString()...");
Console.WriteLine(myObj.ToString());
Console.WriteLine("myObj.ToString() Output.");
Console.ReadKey();
}
Main()中的的代码创建并使用在MyClass.cs中定义的MyClass类的实例。实例化这个类必须使用非默认的构造函数来进行,因为MyClass类的默认构造函数是私有的。
Main()试着给myObj(MyClass的实例)的Val属性赋值。for循环在两次中赋值-1和0,try..catch...结构用于检测抛出的异常。把-1赋给属性时,会抛出System.ArgumentOutOfException类型的异常,catch块中的代码会把改异常的信息输出到控制台窗口中。在下一个循环中,值0成功的赋给了Val属性,通过这个属性再把值赋给私有字段intVal。
3 自动属性
属性是访问对象状态的首选方式,因为他们禁止外部代码实现对象内部的数据存储机制。属性还对内部数据的访问事施加了更多的控制,但是,一般以非常标准的方式属性,即通过一个公共属性来访问一个私有成员。其代码非常类似于前面的代码,这是VS重构工具自动生成的。
重构功能肯定加快了键入的速度,C#还为此提供了另一种方式:自动属性。利用自动属性,可以用简化的语法声明属性,C#编译器会自动添加未键入的内容,具体而言,编译器会声明一个用于存储属性的私有字段,并在属性的get和set块中使用该字段,我们无需考虑细节。
public int MyIntProp
{
get;
set;
}
我们按照通常的方式定义属性的可访问性、类型和名称。但是没有给get和set块提供实现的代码。这些块的实现代码(和底层的字段)由编译器提供。
使用自动属性时,只能通过属性访问数据,不能通过底层的私有字段来访问,我们不知道底层私有字段的名称(该名称是编译期间定义的)。但这并不是一个真正意义上的限制,因为可以直接使用属性名。自动属性的唯一限制是他们必须包含get和set存储器,无法使用这种方法定义只读和只写属性。
标签:
原文地址:http://www.cnblogs.com/DannyShi/p/4475726.html