我有一个看起来像下面这样的类:
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 出现异常呢?当我输出字符串时,我期待一个字符串,而不是很久以前就应该发生的事情的异常,但再次强调:如果它是错误的,它应该尽快失败,即使“很快”已经很晚了。
那么,唯一的异常处理应该在哪里进行呢?我是在寻求“最佳实践”,还是一种品味?
最佳答案
由于 _question 是私有(private)的,因此无需在 ToString() 中检查它是否为 null(除非您只是在检查自己的代码)。
您可以通过让构造函数使用属性 setter 来避免在构造函数中进行检查。因此,我建议:
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 次检查并且仍然为 null 抛出 ArgumentNullException
)。
2. 虽然该方法使用的代码较少,但一个缺点是用户收到的错误消息比将 null 传递给构造函数时稍差一些,因为故障发生在 2 层深度而不是一层。
关于c# - 应该在哪里抛出异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17722356/