个人在多年的开发中对设计有一些自己的想法,在此总结出一些规则希望和大家共同探讨
当然很多设计大家应该已经知道了,当然对于某些设计可能每个人有不同的看法
本系列文章不是为了讨论基本的语法,而是介绍和讨论一些设计的规则
1.在允许的情况下,优先使用父类作为参数类型
其好处是允许该函数有更大的适用范围,有更多的第三方可以调用该方法 (原来持有父类和其他子类变量的第三方现在也可以调用了)
(可别为了更大的参数范围把变量都声明为Object了)
class InputParameter { //如果可以 参数类型优先选择父类 public void Method1(IEnumerablep)//good { } public void Method1(List p)//bad { } }
其好处是,函数不会抛出莫名其妙的“为将对象引用到设置对象的实例” (现在获得的是更准确的信息)
{ public void Method1(string userName) { if (userName == null) { throw new ArgumentNullException("userName"); } //在使用userName之前最好进行检查,userName的值是否合法 } }
(代码如上图所示)既然输入参数非法,那么一定要停止程序的执行,以免在错误的道路上越走越远:)
class InputParameter { public void Method1(string userName) { if (userName == null) { throw new ArgumentNullException("userName"); } if (userName.Length <= 5) { throw new ArgumentOutOfRangeException("userName", "userName 必须大于5个字符"); } //在使用userName之前最好进行检查,userName的值是否合法 } }
准确的参数类型有利于用户知道调用规则 以下面两个例子
如果是string 格式的时间,那么用户就猜不到时间格式了 (时间格式和当前线程的区域有关,也许是 yyyy-MM-dd 也许是 dd/MM/yyyy)
换成DateTime就不会传入错误的时间格式了
class InputParameter { public void Method1(Guid id)//good { } public void Method1(string id)//bad { } public void Method2(DateTime createdTime)//good { } public void Method2(string createdTime)//bad { } }
好处就是调用的时候方便,开发这边也方便
class InputParameter { public void Method1(Guid id) { } public void Method1(Guid id, int type)//good { } public void Method1(int type, Guid id)//bad { } }
7.适当使用默认参数,可以减少开发的成本
public void Method1(Guid id, int type = 1) { }
9.移除一切没有被用到的参数,不要为了以后的扩展预留参数,因为通过重构添加参数的方式是很方便的
10.如果可以,避免使用ref和out参数原因是含有ref和out参数的方法较难和其他方法协作,集成'而且某些不了解该参数行为的人可能会误用该方法;为了更好的设计,建议是不要使用ref和out
也不是完全禁止ref和out,有的时候为了性能原因还是会使用ref和out,以下就是一个例子
string s = "123"; int i = 0; int.TryParse(s,out i);//性能很好,判断字符串是否合法的代码也简单 i = int.Parse(s);//没有发生异常的时候没啥问题....
public class BadRepeatArguments { // Violates rule: ReplaceRepetitiveArgumentsWithParamsArray. public void VariableArguments(object obj1, object obj2, object obj3, object obj4) {} public void VariableArguments(object obj1, object obj2, object obj3, object obj4, object obj5) {} } public class GoodRepeatArguments { public void VariableArguments(object obj1) {} public void VariableArguments(object obj1, object obj2) {} public void VariableArguments(object obj1, object obj2, object obj3) {} public void VariableArguments(params Object[] arg) {} }
如果你想通过某种方式把参数传递到函数内,可是因为种种原因又不能修改方法签名,那么可以采用以下方法
- 第三方类的静态成员,包括Session Cache等
- 如果现有参数类型是类或者结构体,可以直接修改它
- CallContext (该做法不会影响到现有类定义,也不会因为把数据放在共享空间导致冲突)
参考以下代码
class InputParameter { public void Method1() { CallContext.LogicalSetData("parameter1", DateTime.Now); Method2(); } public void Method2() { var createdTime = Convert.ToDateTime(CallContext.LogicalGetData("parameter1")); } }