通常,方法用来呈现动作而属性用来呈现数据。并且属性能够与字段一样被使用,因此说明了属性不应该是复杂的计算或者会导致副作用的。在不违反下列指导方针的时候,考虑属性的使用会胜于方法,因为有较少体验的开发者会发现属性是更加容易被使用的。

如果成员呈现了类型的一个逻辑特性,考虑使用属性。

例如,BorderStyle 就可以作为一个属性,因为边框的样式是 ListView 的一个特性。

如果属性的值被存储在进程的内存中并且属性只提供了对于这个值的访问,那么使用属性要胜于方法。

下列代码范例就说明了这个指导方针。EmployeeRecord 类定义了两个对私有字段进行访问的属性。完整的范例将在本文的最后部分被列出。

public class EmployeeRecord
{private int employeeId;private int department;public EmployeeRecord(){}public  EmployeeRecord (int id, int departmentId){EmployeeId = id;Department = departmentId;}public int Department{get {return department;}set {department = value;}}public int EmployeeId{get {return employeeId;}set {employeeId = value;}}public EmployeeRecord Clone(){return new EmployeeRecord(employeeId, department);}
}
在下列情况下,方法的使用要胜于属性。
  • 操作是比字段集更慢的命令。如果你考虑提供一个异步版本的操作来避免线程的阻塞,那么作为属性来说它将与代价昂贵的操作是非常相似的。尤其是在访问网络或文件系统(不同于一次性的初始化)的时候最应该使用方法,而不是属性。
  • 操作是一个转换(如 Object.ToString 方法)。
  • 操作在每次被调用的时候都返回一个不同的结果,甚至连参数都没有任何变化。例如,NewGuid 方法就在每次被调用的时候都会返回一个不同的值。
  • 操作有一个重大的并且可测的副面作用。注意,操作一个内部的缓存通常不会被认为是一个可测的副面作用。
  • 操作返回一个内部状态(这不包括在堆栈中被返回的对象类型值的复制)的副本。
  • 操作返回一个数组。

在操作返回一个数组的时候使用方法,因为要保护内部数组,所以你应该返回该数组的一个纵深的复制,而不是通过属性而被使用的数组的一个引用。这与开发者把属性当成字段一样来使用的事实是相符合的,并且能够导致非常低效的代码。这就是在下列代码范例中将要被说明的:使用一个属性来返回一个数组。完整的范例将在本文的最后部分被列出。

public class EmployeeData
{EmployeeRecord[] data;public EmployeeData(EmployeeRecord[] data){this.data = data;}public EmployeeRecord[] Employees{get {EmployeeRecord[] newData = CopyEmployeeRecords();return newData;}}EmployeeRecord[] CopyEmployeeRecords(){EmployeeRecord[] newData = new EmployeeRecord[data.Length];for(int i = 0; i< data.Length; i++){newData[i] = data[i].Clone();}Console.WriteLine ("EmployeeData: cloned employee data.");return newData;}
}

开发者使用这个类假设了属性并不是更加昂贵的(相对于字段访问和编写如下代码范例所示的基于这个设想的应用程序代码而言)。

public class RecordChecker
{public static Collection<int> FindEmployees(EmployeeData dataSource, int department){Collection<int> storage = new Collection<int>();Console.WriteLine("Record checker: beginning search.");for (int i = 0; i < dataSource.Employees.Length; i++){if (dataSource.Employees[i].Department == department){Console.WriteLine("Record checker: found match at {0}.", i);storage.Add(dataSource.Employees[i].EmployeeId);Console.WriteLine("Record checker: stored match at {0}.", i);}else {Console.WriteLine("Record checker: no match at {0}.", i);}}return storage;}
}

注意:Employees 属性在每个重复循环中被访问,并且同样也在部门相匹配的时候被访问。在属性每次被访问的时候,都会复制一个被创建的、临时被使用的,然后需要进行垃圾回收的雇员数组。通过把 Employees 实现成一个方法,你可以向开发者表示这个动作是比访问字段时更加昂贵的计算。开发者很有可能只对方法调用一次并且把方法调用的结果进行缓存来完成他们的处理。

范例

下列代码范例说明了假设对属性的访问是廉价的一个完整的应用程序。并且 EmployeeData 类错误地定义了一个返回数组副本的属性。

using System;
using System.Collections.ObjectModel;
namespace Examples.DesignGuidelines.Properties
{public class EmployeeRecord{private int employeeId;private int department;public EmployeeRecord(){}public  EmployeeRecord (int id, int departmentId){EmployeeId = id;Department = departmentId;}public int Department{get {return department;}set {department = value;}}public int EmployeeId{get {return employeeId;}set {employeeId = value;}}public EmployeeRecord Clone(){return new EmployeeRecord(employeeId, department);}}public class EmployeeData
{EmployeeRecord[] data;public EmployeeData(EmployeeRecord[] data){this.data = data;}public EmployeeRecord[] Employees{get {EmployeeRecord[] newData = CopyEmployeeRecords();return newData;}}EmployeeRecord[] CopyEmployeeRecords(){EmployeeRecord[] newData = new EmployeeRecord[data.Length];for(int i = 0; i< data.Length; i++){newData[i] = data[i].Clone();}Console.WriteLine ("EmployeeData: cloned employee data.");return newData;}
}public class RecordChecker
{public static Collection<int> FindEmployees(EmployeeData dataSource, int department){Collection<int> storage = new Collection<int>();Console.WriteLine("Record checker: beginning search.");for (int i = 0; i < dataSource.Employees.Length; i++){if (dataSource.Employees[i].Department == department){Console.WriteLine("Record checker: found match at {0}.", i);storage.Add(dataSource.Employees[i].EmployeeId);Console.WriteLine("Record checker: stored match at {0}.", i);}else {Console.WriteLine("Record checker: no match at {0}.", i);}}return storage;}
}public class Tester{public static void Main(){EmployeeRecord[] records  = new EmployeeRecord[3];EmployeeRecord r0  = new EmployeeRecord();r0.EmployeeId = 1;r0.Department = 100;records[0] = r0;EmployeeRecord r1  = new EmployeeRecord();r1.EmployeeId = 2;r1.Department = 100;records[1] = r1;EmployeeRecord r2  = new EmployeeRecord();r2.EmployeeId = 3;r2.Department = 101;records[2] = r2;EmployeeData empData = new EmployeeData(records);Collection<int> hits = RecordChecker.FindEmployees(empData, 100);foreach (int i in hits){Console.WriteLine("found employee {0}", i);}}}
}

转载于:https://www.cnblogs.com/Laeb/archive/2007/01/30/635057.html

.NET 指南:属性与方法之间的选择相关推荐

  1. vue、Cascader 级联选择、Cascader 属性事件方法、vue Cascader 所有级联选择样式、vue Cascader 级联选择全部属性事件方法

    vue.Cascader 级联选择.Cascader 属性事件方法.vue Cascader 所有级联选择样式.vue Cascader 级联选择全部属性事件方法 Cascader 级联选择 何时使用 ...

  2. python类的方法三种访问权_Python基础33-面向对象(继承资源(属性与方法)的使用注意)...

    在Python中, 继承是指子类对父类资源的使用权 1 继承-属性与方法的使用权限 1.1 测试属性与方法分别如下 公有属性/方法 受保护属性/方法 私有属性/方法 class Animal: a = ...

  3. 前端学习之select控件的使用2,省市县三级联动选择,select控件属性、方法、事件的综合应用...

    总结select控件的属性.方法.事件的使用.数据源使用json数据,包括json数据的遍历. <label for="sheng">省</label> & ...

  4. python类之间方法互相调用_Python中类与类之间属性和方法的调用

    Python中类与类之间属性和方法的调用 class A(object):  #定义一个类 name='python' #类属性 def __init__(self): #实例属性 self.age= ...

  5. java面向对象-------类属性和方法,不同类之间调用

    package java面向对象; /** * 类的创建 */public class Stu { //l类属性 int age; int id; String name; Computer comp ...

  6. vue3组件之间通信(二)——子传父属性和方法

    文章目录 1:setup函数传递属性和方法 (1)子组件传值和方法给父组件 (2)使用ref的方式来在父组件中获取子组件的数据和方法 2:script setup 语法糖传递属性和方法 (1)子组件传 ...

  7. vue3组件之间通信(三)——爷孙组件传递属性和方法

    文章目录 1:setup函数传递属性和方法($attrs) 1:代码 2:主要代码和详细讲解 3:注意点 2:script setup 语法糖传递属性和方法 1:代码 2:主要代码和详细讲解 3:注意 ...

  8. 【Java2】一维数组,家庭收支界面,/属性和方法,方法重载,变量分类,可变参数,包

    文章目录 1.一维数组:int[ ] a = { } 1.1 数组的内存分析(静态):数组名=首地址 1.2 数组的内存分析(动态):元素默认值 1.3 数组相关算法: 1.3.1 找最值:array ...

  9. C#常用控件的属性以及方法(转载)

    -----以前看别人的,保存了下来,但是忘了源处,望见谅. C#常用控件属性及方法介绍 目录 1.窗体(Form) 2.Label (标签)控件 3.TextBox(文本框)控件 4.RichText ...

  10. sklearn中GBDT的一些参数、属性、方法的理解

    文章目录 GBDT 分类器 引入 重要参数 loss learning_rate subsample n_estimators criterion max_depth min_samples_leaf ...

最新文章

  1. java导出为excel文件_java导出数据到excel文件
  2. ShardingSphere-Proxy分库分表以及多租户安装使用
  3. tomcat7自身调优和JVM调优
  4. SPOJ 694 Distinct Substrings(后缀数组)
  5. python123动物重量排序_python基本常识
  6. 【收藏】win10将wsl升级到wsl2
  7. brew mysql 无法启动_MAC OSX brew 升级 mysql5.6到5.7无法启动的问题
  8. 我要带徒弟学写JAVA架构,引路架构师之路
  9. 又掐起来了!余承东称小米环幕屏手机无实用价值,卢伟冰回怼...
  10. 服务 23 年,苹果宣布停止 macOS Server
  11. 教大家抖音怎么开通直播功能
  12. [0]Android框架揭秘-概论
  13. UE4打开屏幕键盘/软键盘/虚拟键盘 无法输入中文
  14. Java反序列化和JNDI注入
  15. fftshift使用
  16. 八爪鱼取消Ajax加载数据,谁知道八爪鱼采集器设置了循环翻页采集怎么才采集十几个数据就停下不动了...
  17. 计算机各个硬盘分区名称不见了,开机后电脑硬盘分区突然消失了,文件都不见了还能找回吗?...
  18. 数学建模竞赛赛前准备及资源分享
  19. 9个超绚丽的HTML5 3D图片动画特效
  20. 阿里云云计算ACP实验考试之使用OSS对图片进行基本处理

热门文章

  1. Maven的Snapshot版本与Release版本
  2. vue开发环境的搭建流程
  3. servlet3.0理解
  4. ajax_demo:GET POST发送数据
  5. table内容保存到Excel中
  6. 【JAVA】虚拟机指令集
  7. Android 启动过程简析
  8. 深入C++中构造函数、拷贝构造函数、赋值操作符、析构函数的调用过程总结
  9. 基于visual Studio2013解决面试题之0909移动星号
  10. flash 与javascrip的t交互和注意事项