32686

FormattedException instead of throw new Exception(string.Format(…)) in .NET

I have been thinking of a good generic exception object that would replace throw new Exception(string.Format("...",...)), to both simplify and also to speed up such objects. The formatting by slow String.Format() should be delayed until Message property is called. Serialization is also somewhat risky. Also, such object could later implement localization.

<strong>Update</strong>: This exception should be inherited by more specific user exceptions, not thrown itself. Sorry for not making this clear.

This is what I have come up with. Please comment if there are any ways to improve it. Thanks!

/// <summary> /// Generic exception capable of delayed message formatting. /// Inherit for more specific exceptions. /// </summary> [Serializable] public class FormattedException : Exception { private readonly object[] _arguments; private readonly string _formatStr; private readonly bool _useFormat; private FormattedException(bool useFormat, Exception inner, string message, params object[] args) : base(message, inner) { _useFormat = useFormat; _formatStr = message; _arguments = args; } public FormattedException() : this(false, null, null, null) {} public FormattedException(string message) : this(false, null, message, null) {} public FormattedException(string message, params object[] args) : this(true, null, message, args) {} public FormattedException(Exception inner, string message) : this(false, inner, message, null) {} public FormattedException(Exception inner, string message, params object[] args) : this(true, inner, message, args) {} public override string Message { get { if (!_useFormat) return _formatStr; try { return string.Format(_formatStr, _arguments); } catch (Exception ex) { var sb = new StringBuilder(); sb.Append("Error formatting exception: "); sb.Append(ex.Message); sb.Append("\nFormat string: "); sb.Append(_formatStr); if (_arguments != null && _arguments.Length > 0) { sb.Append("\nArguments: "); for (int i = 0; i < _arguments.Length; i++) { if (i > 0) sb.Append(", "); try { sb.Append(_arguments[i]); } catch (Exception ex2) { sb.AppendFormat("(Argument #{0} cannot be shown: {1})", i, ex2.Message); } } } return sb.ToString(); } } } #region Serialization private const string SerializationField = "FormatString"; protected FormattedException(SerializationInfo info, StreamingContext context) : base(info, context) { _formatStr = (string) info.GetValue(SerializationField, typeof (string)); // Leave other values at their default } public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); // To avoid any serialization issues with param objects, format message now info.AddValue(SerializationField, Message, typeof (string)); } #endregion }

Answer1:

It's an interesting thought, but not a good idea. The reason to create a custom exception have nothing to do with ease of use - only create a custom exception if someone is going to catch that exception type and do something different with it.

Instead of a custom exception, maybe you can create an extension method.

Answer2:

This,IMO, isn't a very good design.

Just looking at your first parameter for the FormattedException (useFormat) smells bad. If it's NOT a Formatted Exception (useFormat=false), why am I using a FormattedException? That shows bad design. Which basically leads to this: you're abusing inheritance.

You're using inheritance as a form a UTILS class, or some kind of way to have a lot of common and easy functionality in many classes. This is supposed to help you get a DRY approach, except that I feel it isn't a very OO approach. Does this relationship represent "IS A" relationship? I think it doesn't. I think this represents a "Has a" relationship, which means that the class Has an ability to create a formatted exception, instead of a "Is a" formatted Exception.

Maybe an interface is more appropriate? Maybe a decorator pattern? Maybe something else? Have you thought of other solutions other than inheritance?

IMO what you need is a simple Factory (maybe using Extension methods)... which returns whatever type of exception you give it.

Of course this is just my .02 cents, so I might be completely off.

Oh, BTW, those try/catch inside the Exception are making my eyes bleed.

Answer3:

I have a similar class that I have been using for several years, also named FormattedException. One thing you should do is make the class abstract so that is must be inherited by exception classes that use the extended formatting constructor overloads. I would not worry about the performance implications of using String.Format() internally as once an exception is thrown, a much larger impact to overall application performance will take place and the performance impact of a single call to String.Format() is insignificant. I do agree in your overall approach to simplifying the code used to throw exceptions with a formatted string message and I have often found myself embedding a call to String.Format() for the message parameter of many exceptions that I have thrown.

I threw together a project and NuGet package for my version of FormattedException that I have been using and published it on GitHub and NuGet Gallery.

FormattedException source on GutHub

FormattedException NuGet package

Answer4:

Shouldn't you serialize the arguments as well?

Answer5:

Exception handling strategies are based on exception types not exception messages. If you want user to handle your exception you should add meaningful semantic for it. But I truly don't understand how I can handle your exception (expept to show it for the user).

And I think it not a good idea to compute message inside Message property (multiple access to it may cause significant performance drawback). And all your property should behave like fields (here I talked a bit about it).

Recommend

  • Where does 'All' belong in a Makefile?
  • customize error message of throw exception javascript
  • Binding List with datagridview in C#
  • Could not find the following Boost libraries: boost_asio
  • Objective-C – access extern const with a string containing its name? [duplicate]
  • Manage different base layouts in Angular2
  • Passing unspecialized template as a template parameter
  • How can I get the maximum number of OpenMP threads that may be created during the whole execution of
  • springboot + webpack dev server, does not change localhost bundle file after rebuilding
  • Thrust filter by key value
  • Load 24 bit TGA
  • How to merge two Request in Laravel
  • Pointer vs Reference difference when passing Eigen objects as arguments
  • It is possible use the same sql azure instance from two different cloud service of two different sub
  • why my app based on boost::asio didn't accept new connection
  • Opaque reference instead of PImpl. Is it possible?
  • Delphi: Where is the shortcut that started the application? [duplicate]
  • Is there a parser equivalent of 'fragment' marking in ANTLR4?
  • How do I mock an exported typescript function in a jasmine test?
  • Invalid Date on validation Date of js
  • C: Incompatible pointer type initializing
  • Volley JsonObjectRequest send headers in GET Request
  • AES padding and writing the ciphertext to a disk file
  • VS2008 Enable C++ Exception with SEH
  • Javascript convert timezone issue
  • Can I have the cursor start on a particular column by default in jqgrid's edit mode?
  • Rearranging Cells in UITableView Bug & Saving Changes
  • Circular dependency while pushing http interceptor
  • Is there a mandatory requirement to switch app.yaml?
  • retrieve vertices with no linked edge in arangodb
  • Linker errors when using intrinsic function via function pointer
  • Hits per day in Google Big Query
  • How get height of the a view with gone visibility and height defined as wrap_content in xml?
  • Change div Background jquery
  • IndexOutOfRangeException on multidimensional array despite using GetLength check
  • Linking SubReports Without LinkChild/LinkMaster
  • apache spark aggregate function using min value
  • XCode 8, some methods disappeared ? ex: layoutAttributesClass() -> AnyClass
  • Sorting a 2D array using the second column C++
  • java string with new operator and a literal