《Visual C# 程序设计》课程学习(6)——第6章 域、属性与事件
6.1 域
域(Field)又称成员变量(Member Variable),它表示类属性的存储位置,是C#类中不可缺少的一部分。域的声明格式如下:
只读域与readonly关键字
域的声明中如果加上了readonly修饰符表明该域为只读域。只读域只能在域的定义中和它所属类的构造函数中进行修改,在其它情况下是只读的。
readonly只读域具有如下特征:
- 只读域只能在初始化(声明初始化或构造函数初始化)的过程中赋值,因此根据所使用的构造函数,readonly字段可能具有不同的值。
- 只读域可以是实例域也可以是静态域。
- 只读域的类型可以是C#语言的任何类型。
- 因为readonly 是在计算时执行的,它可以用某些变量初始化,也就是readonly的值可以在运行的时候才确定。
- 称之为运行时常数。
const修饰的常量具有如下特征:
- const修饰的常量必须在声明的同时赋值,而且要求编译器能够在编译时期计算出这个确切的值。因此不能从一个变量中提取的值来初始化常量,如果 const int a = b+1;b是一个变量,显然不能再编译时就计算出结果,所以常量是不可以用变量来初始化的。
- const修饰的常量为静态常量,不能够为对象所获取。
- const修饰的值的类型也有限制,它只能为sbyte、byte等。
- 称之为编译时常数。
6.2 属性
为了实现对数据的良好封装,C#为类提供了属性访问函数(简称属性,Property),主要用于控制对域的访问。属性访问函数包括get访问函数和set访问函数,分别用于对域的读取和设置。
6.2.1 属性的声明
C#中属性采用如下方式进行声明:
属性的优点就在于它有良好的封装性。属性不允许外部程序直接访问类的域,而是通过属性访问器进行访问(使用get和set对域值进行读写)。
例如:在User类中可使用Name属性来封装对私有成员变量name的访问。
作为类的特殊函数成员,get和set访问函数需要包含在属性声明的内部,而函数声明只需要写出get和set关键字即可。其中get访问函数没有参数,默认返回类型就是属性的类型,表示属性的返回值;set访问函数的默认返回类型为void,且隐含了一个与属性类型相同的参数value,表示要传递给属性的值。
namespace ConsoleApplication2
{
public class User
{
private string name;
private string sex;
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public string Sex
{
get
{
return sex;
}
set
{
if (value == "男" || value == "女")
{
sex = value;
}
else
{
Console.WriteLine("性别输入不合理!");
}
}
}
}
class Program
{
static void Main(string[] args)
{
User zs = new User();
zs.Name="张三";
zs.Sex="男";
Console.WriteLine("\r\n" + "
姓名:" + zs.Name + " 性别:"
+ zs.Sex);
Console.ReadLine();
}
}
}
6.2.2 属性的分类
根据get和set访问器是否存在,属性可分成如下类型:
- 读写(read-write)属性:同时包含 get 访问器和 set访问器的属性。
- 只读(read-only)属性:只具有 get 访问器的属性。将只读属性作为赋值目标会导致编译时错误。
- 只写(write-only)属性:只具有 set 访问器的属性。除了作为赋值的目标外,在表达式中引用只写属性会出现编译时错误。
练习:在User类中添加两个私有的成员变量,用来表示生日和年龄,并设计相应的属性完成对其的访问,要求生日是只写属性,并能判断出如果用户输入的生日年份小于1900年,或当前年龄小于3岁,给出输入错误提示信息,年龄是只读属性。设计一个测试类来对User类进行使用。
程序运行结果如下所示:
namespace ConsoleApplication1
{
public class User
{ private string name;
private string sex;
private DateTime birthday;
private int age;
public string Name
{
get { return name; }
set { name = value; }
}
public string Sex
{
get { return sex; }
set {
if (value == "男" || value == "女")
{ sex = value; }
else
{ Console.WriteLine("输入不合理!"); }
}
}
public DateTime Birthday //只写属性,设置生日
{
set { birthday = value; }
}
public int Age //只读属性,读取年龄
{
get {
age = DateTime.Now.Year - birthday.Year;
return age;
}
}
}
class Program
{
static void Main(string[] args)
{
User zs = new User();
zs.Name = "张三";
zs.Sex = "男";
zs.Birthday = Convert.ToDateTime("1993-2-1");
Console.WriteLine("姓名:" + zs.Name + "\n性别:" + zs.Sex+"\n年龄:"+zs.Age);
Console.ReadLine();
}
}
}
属性的使用原则
属性与成员变量都可以用来表示事物的状态,但属性可以实现只写或只读并且可以对用户指定的值(value)进行有效性检查,从而保证只有正确的状态才会得到设置,而成员变量不能。所以,在C#中一般采取以下原则:
- (1)若在类的内部记录事物的状态信息,则用成员变量。成员变量一般用private修饰,以防止对外使用。
- (2)对外公布事物的状态信息,则使用属性。属性一般与某个或某几个变量有对应关系。
属性,从外部(类的使用者)来看,类似于类的成员变量。从内部(类的作者)来看,类似于类的方法。
示例:定义一个储蓄账户的类SavingsAccount,并完成该类属性的声明与访问 。 【问题描述】定义一个储蓄账户的类SavingsAccount,该类具有存储帐号(accountNumber)、余额(balance)、已获利息(interestEarned)以及利率(interestRate)等成员。完成该类的构造函数,初始化对象的时候要为该对象设置存储账号和余额。完成相应的属性设置,在主函数中完成该类的实例化及其测试。