次の方法で共有


NotImplementedException vs. NotSupportedException

In responding to a recent blog post, one of the readers, Jeremy Gray, noted that I was using a NotImplementedException where I should have been using a NotSupportedException.  At first I did not agree.  There was a method on an interface which my underlying object could not implement therefore I felt the choice of NotImplementedException was an appropriate.

However I was also not very familiar with NotSupportedException and decided to investigate a bit more.  After all, part of the fun of blogging is being wrong in a very public fashion and this was certainly a golden opportunity.  The post was commenting on API design, what better way to be wrong than with a different API design issue?

After doing a bit of research I agree with Jeremy and draw the following distinction between the two exception types

  • NotSupportedException: Throw this exception when a type does not implement a method for which there is a corresponding property indicating whether or not the method in question is supported.

    For Example:

    • IColletion<T>.Add -> IsReadOnly
    • Stream.Seek -> CanSeek
    • Stream.Write -> CanWrite
  • NotImplementedException: Throw this exception when a type does not implement a method for any other reason.

    For Example: ICollection.Count, ICloneable.Clone, etc ... [1]

The method in question on my previous blog post was ICollection<T>.Add().  I was dealing with an immutable collection for which Add is not possible.  Since there is a property, IsReadOnly, which serves as an indicator that Add() is not allowed, NotSupportedException is the better choice. 

[1] Not implementing these methods is likely a bad idea.

Comments

  • Anonymous
    December 12, 2008
    I only use NotImplemented as a placeholder within stubs, so if I release code with a NotImplementedException, it means I forgot to finish my code (and in fact, VS2008 updated its "Generate Method Stub" functionality to throw that instead of just Exception("This isn't implemented"))

  • Anonymous
    December 12, 2008
    The comment has been removed

  • Anonymous
    December 15, 2008
    I tend to use NotSupported when the functionality will never be available. Usually, that's when it doesn't make "sense" to support it. Your example of Add on a ReadOnlyCollection is a good one. Brad Abrams[1] suggests (but doesn't explicitly state) that you should have a way of checking whether it will throw, but I'm not sure I see that as necessary (nice, yes - but necessary? I'm not convinced.) NotImplemented means that it could be implemented - it just hasn't been. It's either a work in progress, or I didn't think anyone would actually need it, etc. Both NotSupported and NotImplemented should always be thrown by a particular method - it should be the only thing in the method. If there's some object state with which you can't fulfill the contract, then you should use InvalidOperation. It is implemented - just that it's not available right now. [1] http://blogs.msdn.com/brada/archive/2004/07/29/201354.aspx

  • Anonymous
    December 15, 2008
    I like that you make specific mention of the association with another property as it is a strong hint, but I, like Mark, would argue that one should also use NotSupportedException in any case where that member will never be implemented by a given implementation, even without an associated property. I have even bumped into this as a documented requirement for extension points, provider model implementations, etc. that I have encountered from third parties. I tend to summarize the most commonly-used options something like this: This member is not implemented yet but will be very soon = NotImplementedException. This member will never be implemented by this type = NotSupportedException. This member is already implemented but current instance state disallows its use = InvalidOperationException. From there you're off into Argument*Exception, etc. and the list becomes more obvious and correspondingly more tedious to reproduce. :) To me, seeing a given member in a codebase throwing NotImplementedException over a notable period of time is a warning sign, usually suggesting that implementation is required, less frequently suggesting that an entire interface should be dropped and/or that other class refactoring is needed, and least frequently suggesting that it should be changed to NotSupportedException, if only because NotSupportedExceptions should really appear only sparing within any given codebase (since the very existence of NotSupportedException and the patterns for which it is thrown suggests (to me, at least) one or more improperly factored interfaces and/or classes.) Jeremy

  • Anonymous
    December 15, 2008
    @Jeremy, I disagree about NotImplementedException mainly because of existing evidence.  Do a search in the BCL for uses of the empty NotImplementedException constructor.  I'm terrible at counting items in a visual list but I'd say there are 80+ uses of this constructor in the BCL libraries I currently have loaded in reflector.  Based on your definition of NotImplementedException it should not ever appear in an RTM library (unless I'm reading you wrong). The other case is COM libraries.  NotImplementedException is essentially a mapping of E_NOTIMPL into .Net (infact they translate to each other during COM interop).  If you find any non-trivial COM code base it will likely be literred with E_NOTIMPL.   Given that I would argue that NotImplementedException often represents a final state vs a transient one.   It would be nice to have an exception that represented a transient state but I don't believe NotImplementedException could be relied on for this task.