C# 创建我希望处理的自定义异常是一个好主意吗?
创建一个自定义异常是一个好主意吗?当应用程序逻辑发生故障时,该异常将被抛出,并期望得到处理 我想最好是返回一个对象或值;但是: 如果不是,那么在代码中引入一些自定义异常的正确条件是什么C# 创建我希望处理的自定义异常是一个好主意吗?,c#,.net,c++,exception,exception-handling,C#,.net,C++,Exception,Exception Handling,创建一个自定义异常是一个好主意吗?当应用程序逻辑发生故障时,该异常将被抛出,并期望得到处理 我想最好是返回一个对象或值;但是: 如果不是,那么在代码中引入一些自定义异常的正确条件是什么 谢谢 是的,假设您想要创建它的问题确实是一个异常情况(即,如果有,应该很少发生) 如果这是一种正常的错误情况(您预期会定期发生并且是应用程序正常使用的一部分),您应该显式地为其编码—在这种情况下,创建和引发自定义异常是一种代码味道 此外,仅当自定义异常添加信息(在内置异常之上)时,才创建自定义异常 编辑:(以下
谢谢 是的,假设您想要创建它的问题确实是一个异常情况(即,如果有,应该很少发生) 如果这是一种正常的错误情况(您预期会定期发生并且是应用程序正常使用的一部分),您应该显式地为其编码—在这种情况下,创建和引发自定义异常是一种代码味道 此外,仅当自定义异常添加信息(在内置异常之上)时,才创建自定义异常
编辑:(以下评论)
使用异常处理作为流控制的一种形式(即函数X是否正确完成)通常是一个坏主意,并且是一种明确的代码气味。当您希望根据引发的异常类型执行操作时,您应该创建自己的自定义异常。如果您的目的是向用户显示一条消息,那么抛出的异常类型意义不大
但是,在创建自己的异常类型时需要小心,因为.NET平台中已经有许多非常好的异常类型,您应该首先使用其中一种。与JoesBestFileNotFound异常相反,使用FileNotFound异常要好得多。通常,您不应该将异常用于正常的程序逻辑。但是,可以为特定于应用程序的场景创建异常。对于异常处理,有很多好的建议——以本文档为例。如果您查看.NET FW,就会发现有许多异常可以指定某些条件<代码>索引自动边界异常,
未实现异常
等。。。它们都存在,并且是从异常中派生出来的,用于处理异常(双关语并非有意的)情况
例如,在将什么分类为异常与简单地返回null之间划清界限,往往会变得灰色。运用你最好的判断力,努力在团队中保持这种判断力 通常你可以通过标准的例外情况。如果您想提供更多有用的调试信息,boost工具可能会有所帮助 当您希望提供超出其他选项所提供的信息时,或者当您希望用户能够以独特的方式处理时,您希望创建自己的异常。如果你所做的只是提到有一个例外情况,那么就使用已经存在的车轮
我建议总是从std::exception或它的一个派生版本继承。最好的做法是编码时不首先抛出异常。如果你需要一个理由:他们很慢。在大多数情况下,即使是最不雅观的方式,也比围绕它们编码的速度慢得多。也就是说,有时它们是不可避免的,因为其他人编写了代码,或者您确实希望程序在用户面前崩溃(请参阅灾难性故障)。只有在这两种情况下,才能进行异常处理 但这并不意味着将每个
IEnumerable.First()
包装在if(sequence.Count()>0)
中。学习合理地构造代码,这样您就永远不会首先在空序列上调用.First()
。优雅的代码就是胜利
我最近为我的雇主编写了一个快速应用程序,用于自动化系统(用户不坐在键盘旁),必须要求用户在命令行args(想想批处理文件)或配置文件中输入登录信息,否则根据规范,它会故意在他们脸上爆炸。在这种情况下,例外情况是有理由的
下面的所有代码都演示了我的异常哲学
private static string _password;
public static string Password
{
get
{
if (_password.IsNullOrWhiteSpace())
throw new NullReferenceException(string.Format("{0} {1}",
"Password was neither found in the .cfg file nor the",
"command line arguments."));
return _password;
}
set
{
_password = value ?? string.Empty;
}
}
我刚刚编写的扩展方法中的一个无例外编码示例
public static bool All<T>(this IEnumerable<T> list, Func<T, T, bool> func)
{
if (list.Count() < 2)
return true;
T first = list.First();
return list.Skip(1).Aggregate(true, (i, k) => i && func(first,k));
}
奥德,你能不能再打开一点;我想强调的是,在某种程度上滥用异常,这是一种返回其他信息的可选方式。与方法的实际返回类型类似。你明白我的意思了吗?好的!现在我明白你的意思了。你对答案的编辑现在对我来说更清楚了谢谢我和许多其他人不同意您的观点,即异常仅用于异常情况。我建议相反:如果
DocumentLoad
方法在加载文档失败时抛出DocumentFileNotFound
异常,然后,捕获该异常的代码可以知道文档无法加载,因为找不到文档文件。相反,如果只抛出FileNotFoundException
,调用代码将不知道是否找不到文档文件,或者是否找不到DLL、配置文件或其他类似的东西。
public static class ConfigParser
{
public static Dictionary<string, string> PullFromConfigFile()
{
ParallelQuery<Tuple<string, string>> data;
try
{
TextReader tr = new StreamReader("config.cfg");
data = tr.ReadToEnd()
.Split('\n')
.AsParallel()
.Select(i => new string(i.TakeWhile(k => k != '#').ToArray()))
.Where(i => !i.IsNullOrWhiteSpace())
.Select(i => i.Split('\t')
.Where(k => !k.IsNullOrWhiteSpace())
.Select(k => k.Trim())
)
.Where(i => i.Count() == 2)
.Select(i => new Tuple<string, string>(i.First(), i.Last()));
tr.Close();
}
catch (IOException)
{
Logger.Bad("config.cfg file was not found");
return new Dictionary<string, string>();
}
return ConfigParser.ParseIntoDict(data);
}
private static Dictionary<string, string> ParseIntoDict(ParallelQuery<Tuple<string, string>> data)
{
var agg = new Dictionary<string, string>();
foreach (var entry in data)
{
if (!agg.ContainsKey(entry.Item1))
agg.Add(entry.Item1, entry.Item2);
}
var width = agg.Keys.Max(k => k.Length);
agg.ForAll(i => Logger.Log("Loaded Data: {0} {1}",
i.Key.SetWidth(width, '-'), i.Value));
return agg;
}
}
public static class Extensions
{
public static string SetWidth(this string item, int width, char padder, bool right = true)
{
if (item == null)
return new string(padder, width);
if (width > item.Length)
return right ? item.PadRight(width, padder) : item.PadLeft(width, padder);
return item.Substring(0, width);
}
public static bool IsNullOrWhiteSpace(this string str)
{
return string.IsNullOrWhiteSpace(str);
}
}