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


    基本规则
     

    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 和其他第三方文章..

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


  • 相关阅读:
    C#限速下载网络文件
    MVC与WebApi中的异常统一处理
    Javascript闭包(Closure)
    HTML转义字符 Unicode和CSS伪类介绍
    .NET通用工具——正则表达式
    C#的格式化(进制转换|位运算)
    javascript中的类型转换(进制转换|位运算)
    MVC中的七层架构
    Excel中的常用功能
    jQuery基础
  • 原文地址:https://www.cnblogs.com/PurpleTide/p/2208881.html
Copyright © 2020-2023  润新知