注释
此内容由 Pearson Education, Inc. 的许可从 框架设计指南:可重用 .NET 库的约定、习惯和模式(第 2 版)重新打印。 该版于2008年出版,此后该书已于 第三版全面修订。 此页上的一些信息可能已过期。
本部分提供有关参数设计的广泛准则,包括具有检查参数准则的部分。 此外,还应参考 命名参数中所述的准则。
✔️ 请使用提供成员所需的功能的最低派生参数类型。
例如,假设你想要设计一个方法,该方法枚举集合并将每个项打印到控制台。 例如,此类方法应 IEnumerable 用作参数,而不是 ArrayList 或 IList。
❌ 请勿使用保留参数。
如果将来的版本需要对某个成员提供更多输入,可以添加新的重载。
❌ 请勿公开采用指针、指针数组或多维数组作为参数的方法。
指针和多维数组相对难以正确使用。 几乎所有情况下,都可以重新设计 API,以避免将这些类型作为参数。
✔️ 请务必将所有 out
参数置于所有按值和 ref
参数(不包括参数数组)之后,即使它导致重载之间的参数排序不一致(请参阅 成员重载)。
可以将 out
参数视为额外的返回值,并将它们组合在一起,使方法签名更易于理解。
✔️ 在替代成员或实现接口成员时,请在参数命名方面保持一致。
这可以更好地传达方法之间的关系。
在枚举和布尔参数之间进行选择
✔️ 如果不使用枚举,成员会具有两个或更多布尔参数,那么请使用枚举型。
❌ 请勿使用布尔值,除非绝对确定永远不需要两个以上的值。
枚举为将来添加值提供了一些空间,但应注意向枚举添加值的所有影响,枚举 设计中介绍了这些含义。
✔️ 考虑为构造函数参数使用布尔值,这些参数是真正的双状态值,并且只是用于初始化布尔属性。
验证论点
✔️ 请验证传递到公共、受保护或已显式实现的成员的自变量。 如果验证失败,则抛出System.ArgumentException或其子类之一。
请注意,并非一定要在公共成员或受保护成员自身进行实际验证。 在某些私有或内部例程中,它可能发生在较低级别。 要点是被公开给最终用户的整个表面区域都对自变量进行检查。
✔️ 如果传递了 NULL 自变量,而成员不支持 NULL 自变量,则引发 ArgumentNullException。
✔️ 请验证枚举参数。
不要假定枚举参数位于枚举定义的范围内。 CLR 允许将任何整数值转换为枚举值,即使该值在枚举中未被定义。
❌ 不要使用 Enum.IsDefined 进行枚举范围检查。
✔️ 请注意,可变参数在验证后可能已更改。
如果成员对安全敏感,则建议你创建副本,然后验证并处理参数。
参数传递
从框架设计器的角度来看,有三个主要的参数组:按值参数、 ref
参数和 out
参数。
当自变量通过按值参数传递时,成员会收到传入的实际自变量的副本。 如果参数是值类型,则参数的副本将放在堆栈上。 如果参数是引用类型,则引用的副本将放在堆栈上。 最常用的 CLR 语言(如 C#、VB.NET 和 C++),默认按值传递参数。
当参数通过 ref
参数传递时,成员会收到对传入的实际参数的引用。 如果参数是值类型,则对参数的引用将放在堆栈上。 如果参数是引用类型,则对引用的引用将放在堆栈上。
Ref
参数可用于允许成员修改调用方传递的参数。
Out
参数类似于 ref
参数,存在一些细微的差异。 该参数最初被视为未分配,在为其分配值之前,不能在成员体中读取该参数。 此外,必须在成员返回之前为参数分配一些值。
❌ 避免使用 out
或 ref
参数。
使用 out
或 ref
参数需要具有指针的经验、了解值类型和引用类型的差异,以及处理具有多个返回值的方法。 另外,out
和 ref
参数之间的区别并未得到广泛了解。 面向普通受众的框架架构师不应期望用户精通使用 out
或 ref
参数。
❌ 请勿按引用来传递引用类型。
规则存在一些有限的例外,例如可用于交换引用的方法。
具有可变参数数的成员
可以通过提供一个数组参数来表示能够接受可变数量参数的成员。 例如, String 提供以下方法:
public class String {
public static string Format(string format, object[] parameters);
}
然后,用户可以调用该方法 String.Format ,如下所示:
String.Format("File {0} not found in {1}",new object[]{filename,directory});
将 C# 参数关键字添加到数组参数会将参数更改为所谓的参数数组参数,并提供创建临时数组的快捷方式。
public class String {
public static string Format(string format, params object[] parameters);
}
通过执行此作,用户可以通过直接在参数列表中传递数组元素来调用该方法。
String.Format("File {0} not found in {1}",filename,directory);
请注意,参数关键字只能添加到参数列表中的最后一个参数。
✔️ 如果希望最终用户传递具有少量元素的数组,请考虑将 params 关键字添加到数组参数。 如果预期会在常见方案中传递大量元素,则用户可能不会内联传递这些元素,因此不需要参数关键字。
❌ 如果调用方几乎总是已在数组中具有输入,那么请不要使用 params 数组。
例如,具有字节数组参数的成员几乎永远不会通过传递单个字节来调用。 因此,.NET Framework 中的字节数组参数不使用 params 关键字。
❌ 如果通过采用 params 数组参数的成员修改数组,那么请勿使用 params 数组。
由于许多编译器将参数转换为调用站点中的临时数组,因此该数组可能是一个临时对象,因此对数组所做的任何修改都将丢失。
✔️ 请考虑在简单重载中使用 params 关键字,即使更复杂的重载无法使用它。
请自我提问,了解用户即使不在所有重载中使用 params 数组,是否也会在一个重载中使用它。
✔️ 请尝试对参数进行排序,以便可以使用 params 关键字。
✔️ 请考虑在性能极其敏感的 API 中针对参数数量较少的调用提供特殊重载和代码路径。
这样就可以避免在使用少量参数调用 API 时创建数组对象。 采用数组参数的单一形式并添加数字后缀,形成参数的名称。
只有要对整个代码路径进行特殊处理,而不仅仅是创建数组并调用一个更常规的方法时,才应执行此操作。
✔️ 请注意,null 可以作为参数数组参数传递。
在处理之前,应验证数组是否不为 null。
❌ 请勿使用方法 varargs
,否则称为省略号。
某些 CLR 语言(如C++)支持传递称为 varargs
方法的变量参数列表的替代约定。 不应在开发框架中使用该约定,因为它不符合 CLS 标准。
指针参数
通常,指针不应出现在设计良好的托管代码框架的公共外围区域。 在大多数情况下,应封装指针。 但是,在某些情况下,出于互作性原因,需要使用指针,在这种情况下使用指针是合适的。
✔️ 请对采用指针自变量的所有成员提供替代约定,原因是指针不符合 CLS。
❌ 避免对指针参数执行昂贵的参数检查。
✔️ 在设计包含指针的成员时,请遵循与指针相关的常见约定。
例如,无需传递起始索引,因为简单的指针算术可用于完成相同的结果。
部分内容 © 2005, 2009 Microsoft 公司。 保留所有权利。
获得皮尔逊教育公司许可后重印自 框架设计准则:可重用 .NET 库的约定、习惯和模式 ,由 Krzysztof Cwalina 和 Brad Abrams 编写,并作为微软 Windows 开发系列中的出版物之一,于 2008 年 10 月 22 日由 Addison-Wesley Professional 出版。