在 .Net/C# 中抛出多个异常
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/278466/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Throwing multiple exceptions in .Net/C#
提问by Jason Hymanson
In an application I work on, any business logic error causes an exception to be thrown, and the calling code handles the exception. This pattern is used throughout the application and works well.
在我处理的应用程序中,任何业务逻辑错误都会导致抛出异常,调用代码处理异常。这种模式在整个应用程序中使用并且运行良好。
I have a situation where I will be attempting to execute a number of business tasks from inside the business layer. The requirement for this is that a failure of one task should not cause the process to terminate. Other tasks should still be able to execute. In other words, this is not an atomic operation. The problem I have is that at the end of the operation, I wish to notify the calling code that an exception or exceptions did occur by throwing an exception. Consider the following psuedo-code snippet:
我有一种情况,我将尝试从业务层内部执行许多业务任务。这样做的要求是一项任务的失败不应导致进程终止。其他任务应该仍然能够执行。换句话说,这不是原子操作。我遇到的问题是,在操作结束时,我希望通过抛出异常来通知调用代码确实发生了一个或多个异常。考虑以下伪代码片段:
function DoTasks(MyTask[] taskList)
{
foreach(MyTask task in taskList)
{
try
{
DoTask(task);
}
catch(Exception ex)
{
log.add(ex);
}
}
//I want to throw something here if any exception occurred
}
What do I throw? I have encountered this pattern before in my career. In the past I have kept a list of all exceptions, then thrown an exception that contains all the caught exceptions. This doesn't seem like the most elegant approach. Its important to preserve as many details as possible from each exception to present to the calling code.
我扔什么?我以前在职业生涯中遇到过这种模式。过去我保存了所有异常的列表,然后抛出一个包含所有捕获异常的异常。这似乎不是最优雅的方法。从每个异常中保留尽可能多的细节以呈现给调用代码很重要。
Thoughts?
想法?
Edit: The solution must be written in .Net 3.5. I cannot use any beta libraries, or the AggregateException in .Net 4.0 as mentioned by Bradley Grainger(below) would be a nice solution for collection exceptions to throw.
编辑:解决方案必须用 .Net 3.5 编写。我不能使用任何 beta 库,或者Bradley Grainger(如下)提到的 .Net 4.0 中的 AggregateException将是抛出集合异常的一个很好的解决方案。
采纳答案by Bradley Grainger
The Task Parallel Library extensionsfor .NET (which will become part of .NET 4.0) follow the pattern suggested in other answers: collecting all exceptions that have been thrown into an AggregateException class.
.NET的任务并行库扩展(将成为 .NET 4.0 的一部分)遵循其他答案中建议的模式:收集已被抛出到 AggregateException 类中的所有异常。
By always throwing the same type (whether there is one exception from the child work, or many), the calling code that handles the exception is easier to write.
通过始终抛出相同的类型(无论是来自子工作的一个异常还是多个异常),处理异常的调用代码更容易编写。
In the .NET 4.0 CTP, AggregateException
has a public constructor (that takes IEnumerable<Exception>
); it may be a good choice for your application.
在 .NET 4.0 CTP 中,AggregateException
有一个公共构造函数(需要IEnumerable<Exception>
);它可能是您应用的不错选择。
If you're targeting .NET 3.5, consider cloning the parts of the System.Threading.AggregateException
class that you need in your own code, e.g., some of the constructors and the InnerExceptions property. (You can place your clone in the System.Threading
namespace inside your assembly, which could cause confusion if you exposed it publicly, but will make upgrading to 4.0 easier later on.) When .NET 4.0 is released, you should be able to “upgrade” to the Framework type by deleting the source file containing your clone from your project, changing the project to target the new framework version, and rebuilding. Of course, if you do this, you need to carefully track changes to this class as Microsoft releases new CTPs, so that your code doesn't become incompatible. (For example, this seems like a useful general-purpose class, and they could move it from System.Threading
to System
.) In the worst case, you can just rename the type and move it back into your own namespace (this is very easy with most refactoring tools).
如果您的目标是 .NET 3.5,请考虑System.Threading.AggregateException
在您自己的代码中克隆您需要的类部分,例如,一些构造函数和 InnerExceptions 属性。(你可以将你的克隆System.Threading
放在你的程序集中的命名空间中,如果你公开它可能会引起混淆,但会让以后升级到 4.0 更容易。)当 .NET 4.0 发布时,你应该能够“升级”到通过从项目中删除包含您的克隆的源文件,将项目更改为面向新框架版本,然后重新构建框架类型。当然,如果您这样做,您需要在 Microsoft 发布新的 CTP 时仔细跟踪对此类的更改,以免您的代码变得不兼容。(例如,这似乎是一个有用的通用类,他们可以将它从System.Threading
到System
.) 在最坏的情况下,您只需重命名类型并将其移回您自己的命名空间(这对于大多数重构工具来说非常容易)。
回答by Cristian Libardo
No super-elegant solution here but a few ideas:
这里没有超级优雅的解决方案,但有一些想法:
- Pass an error-handler function as argument to DoTasks so the user can decide whether to continue
- Use tracing to log errors as they occur
- Concatenate the messages from the other exceptions in the exception bundle's message
- 将错误处理函数作为参数传递给 DoTasks,以便用户可以决定是否继续
- 使用跟踪记录发生的错误
- 在异常包的消息中连接来自其他异常的消息
回答by Cristian Libardo
You might want to use a BackgroundWorkerto do this for you. It automatically captures and presents any exceptions when completed, which you could then throw or log or do whatever with. Also, you get the benefit of multithreading.
您可能希望使用BackgroundWorker为您执行此操作。它在完成时自动捕获并呈现任何异常,然后您可以抛出或记录或执行任何操作。此外,您还可以获得多线程的好处。
The BackgroundWorker is a nice wrapper around delegate's asynchronous programming model.
回答by Gene
You could create a custom Exception that itself has a collection of Exceptions. Then, in your Catch block, just add it to that collection. At the end of your process, check if the Exception count is > 0, then throw your custom Exception.
您可以创建一个自定义异常,它本身具有一组异常。然后,在您的 Catch 块中,将其添加到该集合中。在您的流程结束时,检查异常计数是否 > 0,然后抛出您的自定义异常。
回答by Hath
Two ways of the top of my head would be either make a custom exception and add the exceptions to this class and throw that the end :
我头顶的两种方法是创建自定义异常并将异常添加到此类并抛出结束:
public class TaskExceptionList : Exception
{
public List<Exception> TaskExceptions { get; set; }
public TaskExceptionList()
{
TaskExceptions = new List<Exception>();
}
}
public void DoTasks(MyTask[] taskList)
{
TaskExceptionList log = new TaskExceptionList();
foreach (MyTask task in taskList)
{
try
{
DoTask(task);
}
catch (Exception ex)
{
log.TaskExceptions.Add(ex);
}
}
if (log.TaskExceptions.Count > 0)
{
throw log;
}
}
or return true or false if the tasks failed and have a 'out List' variable.
或者,如果任务失败并且有一个“out List”变量,则返回 true 或 false。
public bool TryDoTasks(MyTask[] taskList, out List<Exception> exceptions)
{
exceptions = new List<Exception>();
foreach (MyTask task in taskList)
{
try
{
DoTask(task);
}
catch (Exception ex)
{
exceptions.Add(ex);
}
}
if (exceptions.Count > 0)
{
return false;
}
else
{
exceptions = null;
return true;
}
}