【设计原则和建议】 方法返回值

基本规则
 

1.不要忽略返回值;如果不想处理返回值,就选择没有返回值的方法(如果有的话)
 

2.公开给第三方的方法返回值类型在满足功能的情况下,尽量选择父类和接口,而不是具体类型 (面向对象的封装性)

  • 这点可能有很大的争议,我区分为对外的和对内的方法 (对内请看No.3)
  • 返回子类,意味要把子类的细节也暴露出去
  • 使用接口返回具体类型,就不用暴露细节了
    public class ClassP //请忽略嵌套类的设计问题
{
protected internal class User : IUser//我不想暴露User类的细节给外部 注:也可能是private等的访问性
{
public void ResetMoney() { }
}
public IUser GetUser()
{
return new User();
}
}
public interface IUser
{

}
class Program
{
static void Main(string[] args)
{
ClassP p = new ClassP();
var user = p.GetUser();
}
}

  • 下面又是一个返回具体类型的悲剧(一般不建议直接暴露内部集合成员,而是使用Clone等方法返回副本,或者使用 IEnumerable<T>)
    class Program
{
static void Main(string[] args)
{
ClassS s = new ClassS();
var list = s.GetList();
s.PrintListCount();
list.Add("string");
s.PrintListCount();//这里输出1个, ClassS的内部变量被改变了,破坏了封装性
}
}
public class ClassS
{
private List<string> list = new List<string>();
public List<string> GetList()//bad
{
return list;
}
public IEnumerable<string> GetList2()//good
{
return list;
}
public void PrintListCount()
{
Console.WriteLine(list.Count());
}
}
  • 有时候为了保持行为的一致性而选择返回父类 ( WebRequest HttpWebRequest.Create(string requestUriString);)

3.内部方法(如private)尽可能选择详细类型

  • 调用方得到更多细节信息,可以做更多的操作
  • 除非是设计上使用了工厂模式等设计方式,那只能返回接口或者父类了 (返回类型是父类,实际类型还是子类)


4.建议将返回值存在本地变量以后再使用

  • 链式表达式是例外情况

5.将接口作为返回值,往往意味着该设计希望解耦合


6.别为了方便或者是懒惰把方法返回值都弄成Object


7.优先使用返回值,而不是ref和out参数 


8.参数类型和方法名保持一致

  • 如果是链式表达式,自然返回值类型和类本身保持一致

 IQueryable<ClassX> list = null;//只是为了演示  所以没有值
var data = list.OrderBy(p => p.Age).Where(p => p.Type == 1).ToList();




返回值和异常


1.为什么选择异常

  • 一般情况下,在内部使用的方法中,使用异常来提示执行错误,而不是用返回值
  • 所谓内部使用的意思是:该方法不是公开给第三方使用的(例如 组件开发中的public方法, 例如WebService 等)
  • 异常不影响正常逻辑代码的阅读,也不影响返回值本身的意义(例如 你不需要声明一个返回值的类 同时返回 状态码 异常信息 和真正的数据)
  • 相比于返回值,异常的功能信息更为丰富,例如携带堆栈跟踪等
  • 相比于返回值,异常的功能更为强大, 例如通过 AppDomain.CurrentDomain.UnhandledException 处理所有未处理的异常
  • 使用异常来告知执行失败和.net类库本身保持行为一致 例如: System.IO.File.WriteAllText() ;
  • 如果使用返回值类通知执行失败,用户容易忽略返回值,如下所示
            static void Main()
    {
    GoGoGo();//没注意到返回值是false
    //继续....
    }

    static bool GoGoGo()
    {
    return false;
    }
     


2.为什么选择返回值

  • 外部使用方法中应该使用返回值而不是异常,包括但不仅限于Socket,HTTP,跨语言,跨进程的通信
  • asp.net本身 还有WCF 都提供了全局的handler将错误转化为返回的html或者xml (就是我们经常见到的黄色错误页面)  在程序内部使用异常,准备返回的时候使用统一的handler处理为返回值是一个较好的实践
  • 性能问题; 就是为了性能问题.net类库提供了 Int.TryPrase 方法



返回值类型和值


1. void无返回值

  • 不要为了增加返回值而增加返回值,一个东西它如果逻辑上不需要返回值那么就应该设计为void


2.Int 和其他所有的数值类型

  • 在数据逻辑上只能是正整数0的时候,使用-1 作为条件不成立的值. 例如String.IndexOf  返回-1代表字符串不存在
  • 在数据逻辑上是整数的时候,使用 Int?   (Nullable<int>) 并且值为null 作为条件不成立.  例如  int? GetUserId() 用户不存在的时候返回Null (更推荐的方法是先调用方法判断用户是否存在,  然后调用 int GetUserId())


3.String

  • 将null作为条件不成立或者无数据的表示
  • 传递给表现层的返回值考虑返回空字符串 "" (String.Empty) 优先于null   (例如在asp.net页面上直接调用 s.Trim() 等方法会比较方便,不需要判断null值)  我个人觉得这不算一个严谨的设计 但是会方便编码


4.所有普通的Class (非集合类)

  • 将null作为条件不成立或者无数据的表示


5.集合类

  • 将集合类型不为null但是数量为0的集合,作为条件不成立或者无数据的表示


6.泛型

  • 将Default(T) 作为条件不成立或者无数据的表示

部分内容引用自MSDN,FxCop 和其他第三方文章..

因为本人水平有限,如有遗漏或谬误,还请各位高手指正


posted on 2011-10-14 19:53  听说读写  阅读(3088)  评论(6编辑  收藏  举报

导航