簡體   English   中英

應該在哪里拋出異常?

[英]Where should exceptions been thrown?

我有一堂課,看起來像下面這樣:

public class StackOverflowQuestion {

    private string _question;

    public string Question {
        get { return _question;  }
        set { _question = value; }
    }

    public StackOverflowQuestion(string question) {
        _question = question;
    }

    public override string ToString() {
        return _question;
    }
}

現在,不允許將值“ question”設置為null或為空,並且應通過ArgumentNullException通知用戶-但應將其扔到哪里? 根據“快速失敗”原則->無處不在。

public class StackOverflowQuestion {

    private string _question;

    public string Question {
        get { return _question;  }
        set { 
           if(!String.IsNullOrEmpty(value))
                _question = value
            else throw new ArgumentNullException("value");
        }
    }

    public StackOverflowQuestion(string question) {
        if(!String.IsNullOrEmpty(question))
            _question = question;
        else throw new ArgumentNullException("question");
    }

    public override string ToString() {
        if(!String.IsNullOrEmpty(_question)) return _question;
        else throw new ArgumentNullException("_question");
    }
}

現在,這顯然是荒謬的,並且是非常重復的。 但這似乎是正確的:如果通過.ctor設置了該值,則經過短暫檢查后,該值將立即失敗。 當通過屬性設置它時,它會在短暫檢查后直接失敗..但是誰會期望setter發生異常? 當我輸出字符串時,我期望的是一個字符串,不是很早就應該發生的異常,而是再次出現:如果錯了,即使'soon'已經很晚了,它也應該盡快失敗。

那么,唯一的異常處理應該在哪里完成呢? 我是否要求“最佳做法”,或者這是有味道的事情?

由於_question是私有的,因此不需要在ToString()中檢查它是否為null(除非您只是在理智地檢查自己的代碼)。

您可以通過使構造函數使用屬性設置器來避免在構造函數中進行檢查。 因此,我建議:

public class StackOverflowQuestion {

    private string _question;

    public string Question {
        get { return _question;  }
        set { 
           if(string.IsNullOrEmpty(value))
                // to make this more transparent when thrown through the constructor, it might
                // be preferable to throw a real error message like "Question: cannot be null or empty"
                throw new ArgumentException("value");
           this._question = value;
        }
    }

    public StackOverflowQuestion(string question) {
        this.Question = question;
    }

    public override string ToString() {
        return this.Question;
    }
}

需要注意的幾件事:1.對於空字符串,應該拋出ArgumentException而不是ArgumentNullException (如果您願意,可以進行2次檢查,並且仍然將ArgumentNullException拋出為null)。 2.雖然該方法使用的代碼更少,但一個缺點是,用戶收到的錯誤消息比將null傳遞給構造函數時要差一些,因為失敗發生的深度是2級而不是1級。

您只需對它進行一次測試-在設置變量的單個位置,將構造函數更改為使用該屬性:

public class StackOverflowQuestion
{
    private string _question;

    public string Question
    {
        get { return _question; }
        set
        { 
           if (String.IsNullOrEmpty(value))
           {
               throw new ArgumentException("Question cannot be null or empty",
                                           "value");
           }
           _question = value;
        }
    }

    public StackOverflowQuestion(string question)
    {
        Question = question;
    }

    public override string ToString()
    {
        return Question;
    }
}

這里的一個缺點是“壞參數”名稱將是value而不是在構造函數中為空時的question ,但我認為這是值得付出的代價。 一種替代方法是使用消息,而不指定參數名稱。

可能希望將nullempty分開,以便可以在ArgumentNullException為null時拋出它-但當它為空時,則不應拋出ArgumentNullException

獲取值時,您無需執行任何檢查,因為您知道它永遠不會為null或為空,因為您正在阻止以這種方式進行設置。

您還應該考慮是否可以使該類不可變,這時您只需要在構造函數中進行測試,因為不會有設置器。

我寧願使其不變:

public class StackOverflowQuestion
    {
        public string Question
        {
            get; private set;
        }

        public StackOverflowQuestion(string question)
        {
            if (String.IsNullOrEmpty(question))                
              throw new ArgumentNullException("question");

            Question = question;
        }

        public override string ToString()
        {
            return Question;
        }
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM