a) 成员重载
要尽量用描述性的参数名来说明较短的重载中使用的默认值
在一族对参数的数量进行重载的成员中,较长的重载应该用参数名来说明与之对应的较短重载所使用的默认值。这最适用于布尔参数。
比如
public MethodInfo GetMethod(string name) //默认不区分大小写
public Methodinfo GetMethod(string name, bool ignoreCase) //是否区分大小写
如果使用枚举而不是布尔做参数的话会更容易让人理解。
避免在重载时随意给参数命名。如果有两个重载中的某个参数表示相同的输入,那么参数名应该相同
public int IndexOF(string value )
public int IndexOF(strign value, int startIndex)
避免使重载成员的参数顺序不一致。在所有重载中,同名参数应该出现在相同位置。
要把最长的重载做成虚函数(如果需要扩展性)
较短的重载应该仅仅是调用较长的重载
这个模式也可以运用于抽象类,在抽象类中,你可以在非虚,非抽象的方法中执行所有必须的参数检查,然后提供一个抽象方法让开发人员去实现。这么做的好处就是,抽象方法被重写后,非虚,非抽象的方法不必修改,同时由于参数检查是放在非虚,非抽象的方法里的,所以也只需写一次就可以了。
不要在重载成员中使用ref或者out修饰符
一些编程语言无法识别这样的重载调用。此外这样的重载通常具有完全不同的意义,他们很有可能不应该是重载,应该是独立的方法,
要允许可选参数为null
如果方法有可选的引用类型参数,那么要允许它为null,以表示应该使用默认值。这就避免了在调用API前必须检查参数是否为null的问题。如下所示
If(geometry == null)
DrawGeometry(brush, pen);
Else
DrowGeometry(brush, pen, geometry);
当然,这不是鼓励我们把null当作神奇的常量来使用,而是为了避免显式的检查。事实上,在调用API时必须使用null就表明你的代码有错误,或者说框架没有提供合适的重载。
b) 显示地实现接口成员
接口成员显式的实现使得客户端代码在调用我们实现的接口成员时,必须把实例强制转换为接口类型。
案例:
Public struc Int32:Iconvertible
{
Int Iconvertible.ToInt32(){…}
}
使用的使用:
Int i=0;
((IConvertible)i).ToInt32;
避免显示地实现接口成员,如果没有很强的理由
显式的实现接口成员可能会把开发人员搞糊涂,因为这些成员不会出现在公有成员列表中,而且对值类型来说还可能导致不必要的装箱。
一般来说,需要显示地实现接口的方法的原因是类型已经有了另一个方法了,该方法与接口方法相同,但是返回类型不同。
考虑在需要隐藏一个成员并增加玲玲一个名字更适合的等价成员时,显示地实现接口成员。
可以说这是相当于对成员进行重命名。
例如
public class FileStream:Idisposable
{
Idisposable.Dispose(){this.Close()};
punlic void Close(){}
}
像这样的成员重命名应该少用,大多数情况下,与不够理想的接口成员名字相比,重命名所带来的混乱是更大的问题。
c) 属性和方法之间的选择
根据属性和方法的使用,我们可以在高层次API设计风格分为两种。
一种是侧重方法的API。在这种风格的API中,方法有许多参数,而类型的属性则比较少
Public aaa(string a,string b, string c)
另一种是侧重属性的API,在这种风格的API中,方法有比较少的参数,但是有较多的属性来控制方法的语义
Public aaa(){}
Public string a{}
Public string b{}
Public string c{}
一般来说,许多参数的方法会导致许多重载。如果要得到每种的组合,那么就得有多种重载。这样的API很难让人理解。
如果要添加新的API特性,那么就必须添加更多的重载。
属性提供了一种自然的方式,使得PI能够字说明,易于完成声明、同时版本比较好管理。
然后值得注意的是,侧重方法的设计在性能方面有优势。
经验法则是,方法应该表示操作,而属性应该表示数据。如果其他各个方面都一样,那么就该优先使用属性而不是方法。
要使用属性而不是要使用方法---------如果属性的值存放在内存中,而且提供属性的目的仅仅是为了访问该值。
要在下列情况中使用方法而不是使用属性
1、 该操作比字段访问要慢一个或多个数量级
2、 该操作是一个转换操作,比如Object.ToString()方法
3、 该操作每次返回的结构不同,即使传入的参数不变。比如Guid.NewGuid()
4、 该操作返回一个数组
返回数组的属性很容易误导用于。通常返回内部数组的副本是必须的,这样用户就无法改变内部状态,但是这会导致低效代码。
比如下面的代码,假设你的数组属性返回的是一个副本的话,那么下面的属性被返回了两次那么这么一小段代码就会产生2n+1个副本
for( int i=0; i <microsoft.Employees.Length;i++)
...{
if(microsoft.Employees[i].Alias == “kcwalina”)
return;
}
这个问题可以用以下两种方式解决
1、 把属性改成方法,这可以告诉调用者该操作不只是访问内部字段,还有可能在每次调用时创建一个数组。这样一来,用户很可能智慧调用一次该方法,把结果咱数保存起来,并对保存结果进行操作。
2、 把属性的返回值改成集合而不要使用数组。我们可以用ReadOnlyCollection<T>来提供对私有数组的公有只读访问。
public ReadOnlyCollection<Employee>Employees
{
get{return roEmployees;}
}
private Employee[] employee;
private ReadOnlyCollection<Employee> roEmployees;