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 appl
The Task Parallel Library extensions for .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.
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); it may be a good choice for your application.
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).