一周学会 C# (属性一)
C# 才鸟( QQ:249178521 )
1. 问题
- ** 原始的封装是麻烦的 ** ** **
** struct Time **
** { **
** ... **
** public int GetHour() **
** { **
** return hour; **
** } **
** public void SetHour(int value) **
** { **
** hour = value; **
** } **
** ... **
** private int hour, minute, second; **
** } **
** static void Main () **
** { **
** Time lunch = new Time(); **
** lunch.SetHour(12); **
** Console.WriteLine(lunch.GetHour()); **
** } **
封装把一些不重要的细节隐藏起来,这样你可以集中精力处理那些重要的内容。但封装很难被掌握,一个典型的封装误用是盲目地把公有字段转为私有字段。例如在上面的例子中,程序定义了一个私有字段 hour 和 SetHour 函数和 GetHour 函数,而不是定义一个公有的 hour 字段。如果 GetHour 函数只是返回私有字段的值而 SetHour 函数只是设置私有字段的值的话,那么你除了使 Time 类更难使用外,你不会得到任何好处。
2. 不是解决的办法
· ** 如果字段是公有的,那使用起来是简单的 ** ** **
w ** 但如果你使用公有字段的话,你会失去控制权 ** ** **
w ** 要简化而不是简单 ** ** **
** struct Time **
** { **
** ... **
** public int Hour; **
** public int Minute; **
** public int Second; **
** } **
** static void Main () **
** { **
** Time lunch = new Time(); **
** lunch.Hour = 30; **
** lunch.Minute = 12; **
** lunch.Second = 0; **
** ... **
** } **
上面的例子使用公有字段来使字段的使用比较简单。例如,你不用写:
lunch.SetHour(lunch.GetHour() + 1);
而只要写:
++lunch.Hour;
但是,这种简单的表达式是有代价的。考虑上面的例子,程序给 Hour 和 Minute 字段分别赋值为 30 和 12 。问题是 30 不在 Hour 的范围( 0-23 )内。但如果字段是公有的话,你就没有办法捕获这个错误。
所以虽然 get 和 set 函数比较麻烦,但它们在这方面比公有字段具有优势是很明显的。 get 和 set 函数允许程序员控制类的内在字段的读和写。这是非常有用的,例如你可以检查 set 函数的参数范围。
当然最理想的方法是保留公有字段提供的简单而直接的表达式和 get 和 set 函数提供的控制权。(呵呵,人总是既想偷懒又想得到很多)
3. 解决的办法
· ** 属性 ** ** **
w ** 自动使用 ** **_ get _ ** ** ** ** 标识符进行读 ** ** **
w ** 自动使用 ** ** set ** ** 标识符进行写 ** ** **
** struct Time **
** { **
** ... **
** public int Hour // ** ** 没有(),是 ** ** H ** ** 而不是 ** ** h **
** { **
** get { ... } **
** set { ... } **
** } **
** private int hour, minute, second; **
** } **
** Time lunch = new Time(); **
** ... **
** lunch.Hour = 12; **
** ... **
** Console.WriteLine(lunch.Hour); **
C# 提供了一个解决上述问题的好办法。你可以把 get 和 set 函数组合成一个简单的属性。属性的声明包括一个可选的访问修饰符 ( 在例子中是 public) 、返回值 (int) 、属性的名字 (Hour) 和一个包含 get 和 set 语句的属性体。特别要注意的是属性没有括号,因为属性不是函数。属性的命名规则应符合一般的命名规则,即公有的使用 PascalCase 规则,而非公有的使用 camelCase 规则。在上面的例子中, Hour 属性是公有的,所以命名为 Hour 而不是 hour 。
例子中演示了属性的用法。属性使用的语法和字段的一样,没有括号。如果你要写一个属性,那你可以这样写:
lunch.Hour = 12;
属性的 set 语句自动被执行。
如果你要读一个属性,你可以这样写:
int hour = lunch.Hour;
属性的 get 语句自动被执行。
4. get 语句
l **_ get _ ** **_ 语句 _ ** ** **
Ø ** 必须返回一个有确定类型的值 ** ** **
Ø ** 功能上就像一个 ** ** “get ** ** 函数 ** ** ” **
** struct Time **
** { **
** ... **
** public int Hour **
** { **
** get **
** { **
** return hour; **
** } **
** ... **
** } **
** private int hour, minute, second; **
** } **
** Time lunch = new Time(); **
** ... Console.WriteLine(lunch.Hour); **
** // ** ** 请注意, ** ** get ** ** 和 ** ** set ** ** 不是关键字 **
当读一个属性的时候,属性的 get 语句自动运行。
get 语句必须返回一个有确定类型的值。在上面的例子中, Time 结构类有一个整型属性 Hour ,所以它的 get 语句必须返回一个整型值。
属性的返回值不能是 void (从这里可以推断出字段的类型也不能是 void )。这就意味着 get 语句必须包含一个完整的 return 语句( retun; 这种形式是错误的)。
get 语句可以在 retun 语句前包含任何其他的语句(比如,可以检查变量的类型) , 但 return 语句不能省略。
注意, get 和 set 不是关键字,所以你可以在任何地方包括 get/set <SPAN style="FONT-FAMILY: 宋