Net面向对象程序设计-15-实现属性以访问字段.ppt_第1页
Net面向对象程序设计-15-实现属性以访问字段.ppt_第2页
Net面向对象程序设计-15-实现属性以访问字段.ppt_第3页
Net面向对象程序设计-15-实现属性以访问字段.ppt_第4页
Net面向对象程序设计-15-实现属性以访问字段.ppt_第5页
已阅读5页,还剩26页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

,.NET面向对象程序设计 第15章 实现属性以访问字段,本章简介,使用属性封装逻辑字段 声明get accessor 声明set accessor 创建声明了属性的接口 使用结构和类实现含有属性的接口 根据字段定义自动生成属性 用属性来初始化对象,15.1 使用方法来实现封装,以下结构用于将屏幕上的一个位置表示成一个(X,Y)坐标对 假定x坐标的取值范围是01280,y的取值范围是01024,private static int rangeCheckedX(int x) if (x 1280) throw new ArgumentOutOfRangeException(“X“); return x; private static int rangeCheckedY(int y) if (y 1024) throw new ArgumentOutOfRangeException(“Y“); return y; ,struct ScreenPosition public int X; public int Y; public ScreenPosition(int x, int y) this.X = rangeCheckedX(x); this.Y = rangeCheckedY(y); ,问题:违反了封装的原则,没有将其数据保持private状态 虽然ScreenPosition构造器会对它的参数进行范围检查,但在创建好一个对象后,就可以随便访问public字段 ScreenPosition origin = new ScreenPosition(0, 0); . int xpos = origin.X; origin.Y = -100; / oops,解决该问题的方法:将字段设为private,并添加一个取值(getr accessor)方法和一个赋值(set accessor)方法,以便分别读取和写入每个private字段的值 然后,赋值方法就可以对新的字段值执行范围检查 缺点:它使用的是不太方便的,基于方法的语法 int xpos = origin.GetX(); origin.SetX(xpos + 10);,struct ScreenPosition . public int GetX() return this.x; public void SetX(int newX) this.x = rangeCheckedX(newX); . private static int rangeCheckedX(int x) . private static int rangeCheckedY(int y) . private int x, y; ,15.2 什么是属性,属性(property)是字段和方法的一个交集:它看起来像是一个字段,行为上又像一个方法 访问一个属性所用的语法和访问一个字段的语法是相同的 编译器会将这种字段风格的语法自动转换成对特定accessor方法的调用,语法: AccessModifier Type propertyName get / read accessor code set / write accessor code ,struct ScreenPosition private int x, y; public ScreenPosition(int X, int Y) this.x = rangeCheckedX(X); this.y = rangeCheckedY(Y); public int X get return this.x; set this.x = rangeCheckedX(value); public int Y get return this.y; set this.y = rangeCheckedY(value); private static int rangeCheckedX(int x) . private static int rangeCheckedY(int y) . ,注意: 所有set accessor都用一个隐藏的、内建的参数来传递要写入的数据 public字段和属性大写,private的字段和属性小写,属性为访问对象内的实例变量及访问另一个对象中的实例变量提供了一致性的语法。 属性与等价的存取器方法执行速度同样快。 当属性的get语句块和set语句块编译成MSIL时,它们都转换成方法。在MSIL中,get语句块由一个名字为get_的方法表示。set同样。,8,15.2.1 使用属性,从ScreenPosition结构的X和Y属性中取值: ScreenPosition origin = new ScreenPosition(0, 0); int xpos = origin.X; / calls origin.X.get int ypos = origin.Y; / calls origin.Y.get 对属性进行赋值,编译器自动将字段风格的代码转换成对该属性的set accessor的调用 origin.X = 40; / calls origin.X.set, with value set to 40 origin.Y = 100; / calls origin.Y.Set, with value set to 100 可以通过static关键字声明静态属性,访问static属性时,要附加类或者结构的名称而不是其实例的名称作为前缀,15.2.2 只读属性,可以声明只包含一个get accessor的属性,即声明了一个只读属性 X属性不包含set accessor,所以,如下操作错误 origin.X = 140; / compile-time error,示例: struct ScreenPosition . public int X get return this.x; ,15.2.3 只写属性,也可以声明只包含一个set accessor的属性,即声明了一个只写属性 X属性不包含get accessor,所以,如下操作错误 Console.WriteLine(origin.X); / 编译器error origin.X = 200; / OK origin.X += 10;/ 编译器error,示例: struct ScreenPosition . public int X set this.x = rangeCheckedX(value); ,只写属性适用于对密码这样的属性进行保护,15.2.4 属性的可访问性,可访问性是在声明属性时指定的,但是,在属性的声明中,可以为get和set单独指定可访问性,struct ScreenPosition 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); private int x, y; ,注意: 定义时,只能改变一个accessor的可访问性 accessor的访问修饰符所指定的可访问性在限制程度上必须大于属性的可访问性 警告: 习惯上,为属性和private字段赋予几乎完全相同的名称,只是首字母大小写有别 但是,要小心使用,class Employee private int employeeID; public int EmployeeID; get return this.EmployeeID; set this.EmployeeID = value; ,15.3 理解属性的局限性,属性在外观、行为和感觉上都类似于字段,但它们本质上是方法,并不是真正的字段 属性的限制: 只有在一个结构或类初始化好之后,才能通过这个结构或类的属性来进行赋值 ScreenPosition location; location.X = 40; / compile-time error, location not assigned 所以,定义结构和类时,一开始就应该使用属性,而不是先用字段,后来又变成属性,字段变成属性后,以前使用了这个类或结构的代码就可能无法正常工作,不能将属性作为一个ref或者out参数值传给一个方法;但可以将一个可写的字段作为ref或out参数值传递,这是因为属性并不真正指向一个内存位置,它代表的是一个方法 在一个属性中,最多只能包含一个get accessor和一个set accessor,属性不能包含其他方法、字段或属性 get accessor和set accessor不能获取任何参数,要赋的值会通过内建的、隐藏的value变量,自动传给set accessor 不能声明const属性,合理使用属性,class BankAccount . public money Balance get . set . private money balance; ,class BankAccount . public money Balance get . public void Deposit(money amount) . public bool Withdraw(money amount) . private money balance; ,15.4 在接口中声明属性,除了可在接口中声明方法之外,还可以定义属性 interface IScreenPosition int X get; set; int Y get; set; 实现该接口的任何类或结构都必须实现X和Y属性,并在属性中定义get和set,struct ScreenPosition : IScreenPosition . public int X get . set . public int Y get . set . . ,在类中实现接口属性时,可以将属性的实现声明为virtual,以允许未来派生的类重写这些实现 例如:,class ScreenPosition : IScreenPosition public virtual int X get . set . public virtual int Y get . set . ,还可以选择使用显式接口实现语法来实现一个属性,属性的显式实现是非公共和非虚的(因而不能被重写),struct ScreenPosition : IScreenPosition int IScreenPosition.X get . set . int IScreenPosition.Y get . set . private int x, y; ,课本276页练习,15.5 生成自动属性,属性的两个主要优势: 与应用程序的兼容性 与接口的兼容性:如果要实现一个接口,而且接口将一个数据项定义成属性,就必须实现这个属性,使之与接口中的规范相符 C#编译器能够自动为属性生成代码 class Circle public int Radius get; set; . 自动生成的属性不可以是 只读或者只写的,class Circle private int _radius; public int Radius get return this._radius; set this._radius = value; . ,15.6 使用属性来初始化对象,public class Triangle private int side1Length; private int side2Length; private int side3Length; public Triangle() this.side1Length = this.side2Length = this.side3Length = 10; public Triangle(int length1) this.side1Length = length1; this.side2Length = this.side3Length = 10; ,public Triangle(int length1, int length2) this.side1Length = length1; this.side2Length = length2; this.side3Length = 10; public Triangle(int length1, int length2, int length3) this.side1Length = length1; this.side2Length = length2; this.side3Length = length3; ,可以使用命名参数,然而更好和更透明的方式是将私有变量初始化为它们的默认值并定义属性,public class Triangle private int side1Length = 10; private int side2Length = 10; private int side3Length = 10; public int Side1Length set this.side1Length = value; ,public int Side2Length set this.side2Length = value; public int Side3Length set this.side3Length = value; ,Triangle tri1 = new Triangle Side3Length = 15 ; Triangle tri2 = new Triangle Side1Length = 15, Side3Length = 20 ; Triangle tri3 = new Triangle Side2Length = 12, Side3Length = 17 ; Triangle tri4=new TriangleSide1Length=9,Side2Length=12,Side3Length = 15 ;,24,应用:使用属性实现延迟初始化和惰性更新,当一个变量很少使用而且它的初始化即浪费时间又浪费资源时,可使用延迟初始化技术。 惰性更新(lazy update),25,实例分析:,为农产品商人编写程序 要求:在合理的精度范围内预测不同地区来年的产量和质量。 相关地区10天内降水量预测是核心参数 每次降水量预测要占用一定的cpu时间 每次计算从零开始,每20秒提供一个更新更准确的预报 不同的作物有不同的种植季节,所以用户在每年的特定时间只需预报其中的几种,而且每次预报只限于几个地区。,26,程序源代码:CropForecaster.cs,01: using System; 02: using System.Timers; 03: 04: class WeatherForecaster 05: 06: public static double CalculateRainfallDay10RegionA() 07: 08: /Simulated complex calculations takes 5000 milliseconds 09: System.Threading.Thread.Sleep(5000); 10: Random randomizer = new Random(); 11: return (double)randomizer.Next(40,100); 12: 13: 14:,27,15: class CropForecaster 16: 17: private double rainfallDay10RegionA; 18: private bool rainfallDay10RegionANeedUpdate = true; 19: 20: public CropForecaster() 21: 22: Timer aTimer = new Timer(); 23: aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent); 24: aTimer.Interval = 20000; 25: aTimer.Enabled = true; 26: 27: 28: public double RainfallDay10RegionA 29: 30: get 31: 32: if (rainfallDay10RegionANeedUpdate) 33: 34: rainfallDay10RegionA = WeatherForecaster.CalculateRainfallDay10RegionA(); 35: rainfallDay10RegionANeedUpdate = false; 36: return rainfallDay10RegionA; 37: 38: else 39: 40: return rainfallDay10RegionA; 41: 42: 43: ,28,45: private double ComplexResultA() 46: 47: /Arbitrary calculation involving lots of calls to rainfallDay10RegionA 48: return (RainfallDay10RegionA / 2) + (RainfallDay10RegionA / 3) + 49: (RainfallDay10RegionA / 4); 50: 51: 52: private double ComplexResultB() 53: 54: /Arbitrary calculation involving even more calls to rainfallDay10RegionA 55: return (RainfallDay10RegionA / 10 - 100) + (RainfallDay10RegionA / 100); 56: 57: 58: public double WheatCropSizeInTonsInRegionA () 59: 60: /More arbitrary calculations returning a nice big result 61: Console.WriteLine(“Commencing forecast calculations. Please wait.“); 62: return (ComplexResultA() / 2 + ComplexResultB() / 4 + 63: ComplexResultA() * 100000; 64: 65: 66: public void OnTimedEvent(object source, ElapsedEventArgs e) 67: 68: /This method is currently called automatically every 20 seconds 69: Console.WriteLine(“nnNew Update NeedednPerform another forecast?“); 70: rainfallDay10RegionANeedUpdate = true; 71: 72: ,29,74: class ForecastTester 75: 76: public static void Main() 77: 78: string answer; 79: CropForecaster myForecaster = new CropForecaster(); 80: 81: Console.Write(“Would you like to perform a crop forecast? Y)es N)o “); 82: answer = Console.ReadLine().ToUpper(); 83: while (!(answer = “N“) 84: 85: Con

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论