【设计原则和建议】 方法输入参数

个人在多年的开发中对设计有一些自己的想法,在此总结出一些规则希望和大家共同探讨

当然很多设计大家应该已经知道了,当然对于某些设计可能每个人有不同的看法

本系列文章不是为了讨论基本的语法,而是介绍和讨论一些设计的规则


1.在允许的情况下,优先使用父类作为参数类型

其好处是允许该函数有更大的适用范围,有更多的第三方可以调用该方法 (原来持有父类和其他子类变量的第三方现在也可以调用了)

(可别为了更大的参数范围把变量都声明为Object了)

 class InputParameter
{
//如果可以 参数类型优先选择父类
public void Method1(IEnumerable<string> p)//good
{
}
public void Method1(List<string> p)//bad
{
}
}


2.如果该方法是公开方法,那么建议检查输入参数是否有效

其好处是,函数不会抛出莫名其妙的“为将对象引用到设置对象的实例” (现在获得的是更准确的信息)

    {
public void Method1(string userName)
{
if (userName == null)
{
throw new ArgumentNullException("userName");
}
//在使用userName之前最好进行检查,userName的值是否合法
}
}


3.如果输入参数不合法,建议终止当前执行并抛出异常

(代码如上图所示)既然输入参数非法,那么一定要停止程序的执行,以免在错误的道路上越走越远:)

    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的值是否合法
}
}


4.如果可以,参数类型要尽可能的准确

准确的参数类型有利于用户知道调用规则 以下面两个例子

如果是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
{
}
}


5.在有重载的时候,最好保证参数顺序 

好处就是调用的时候方便,开发这边也方便

    class InputParameter
{
public void Method1(Guid id)
{
}
public void Method1(Guid id, int type)//good
{
}
public void Method1(int type, Guid id)//bad
{
}
}


6.如果有params参数,那么把它放在最后
 

7.适当使用默认参数,可以减少开发的成本

 public void Method1(Guid id, int type = 1) 
{
}


8.参数名字个人有个人的标准,我个人推荐骆驼命名法
 

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);//没有发生异常的时候没啥问题....


11.如果有若干个同类型同含义对象,建议使用params参数

   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"));
}
}


许多内容引用自MSDN,FxCop 和其他第三方文章..
因为本人水平有限,如有遗漏或谬误,还请各位高手指正

posted on 2011-10-11 10:13  听说读写  阅读(2141)  评论(10编辑  收藏  举报

导航