Why does NotImplementedException exist?

你。 提交于 2019-11-26 06:15:05

问题


This really, really urks me, so I hope that someone can give me a reasonable justification for why things are as they are.

NotImplementedException. You are pulling my leg, right?

No, I\'m not going to take the cheap stab at this by saying, \"hang on, the method is implemented - it throws a NotImplementedException.\" Yes, that\'s right, you have to implement the method to throw a NotImplementedException (unlike a pure virtual function call in C++ - now that makes sense!). While that\'s pretty damn funny, there is a more serious problem in my mind.

I just wonder, in the presence of the NotImplementedException, how can anyone do anything with .Net? Are you expected to wrap every abstract method call with a try catch block to guard against methods that might not be implemented? If you catch such an exception, what the heck are you supposed to do with it??

I see no way to test if a method is actually implemented without calling it. Since calling it may have side effects, I can\'t do all my checks up-front and then run my algorithm. I have to run my algorithm, catch NotImplementedExceptions and the some how roll back my application to some sane state.

It\'s crazy. Mad. Insane. So the question is: Why does the NotImplementedException exist?

As a preemptive strike, I do not want anyone to respond with, \"because designers need to put this in the auto-generated code.\" This is horrid. I would rather the auto-generated code not compile until you supply an implementation. For example, the auto generated implementation could be \"throw NotImplementedException;\" where the NotImplementedException is not defined!

Has anyone ever caught and handled a NotImplementedException? Have you ever left a NotImplementedException in your code? If so, did this represent a time bomb (ie, you accidentally left it there), or a design flaw (the method should not be implemented and will never be called)?

I\'m very suspicious of the NotSupportedException also... Not supported? What the? If it\'s not supported, why is it part of your interface? Can anyone at Microsoft spell improper inheritance? But I might start another question for that if I don\'t get too abuse for this one.

Additional info:

This is an interesting read on the subject.

There seems to be a strong agreement with Brad Abrams that \"NotImplementedException is for functionality that is just not yet implemented, but really should (and will be). Something like what you might start with when you are building a class, get all the methods there throwing NotImplementedException, then flush them out with real code…\"

Comments from Jared Parsons are very weak and should probably be ignored: NotImplementedException: Throw this exception when a type does not implement a method for any other reason.

The MSDN is even weaker on the subject, merely stating that, \"The exception that is thrown when a requested method or operation is not implemented.\"


回答1:


There is one situation I find it useful: TDD.

I write my tests, then I create stubs so the tests compile. Those stubs do nothing but throw new NotImplementedException();. This way the tests will fail by default, no matter what. If I used some dummy return value, it might generate false positives. Now that all tests compile and fail because there is no implementation, I tackle those stubs.

Since I never use a NotImplementedException in any other situation, no NotImplementedException will ever pass onto release code, since it will always make some test fail.

You don't need to catch it all over the place. Good APIs document the exceptions thrown. Those are the ones you should look for.

EDIT: I wrote an FxCop rule to find them.

This is the code:

using System;
using Microsoft.FxCop.Sdk;

/// <summary>
/// An FxCop rule to ensure no <see cref="NotImplementedException"/> is
/// left behind on production code.
/// </summary>
internal class DoNotRaiseNotImplementedException : BaseIntrospectionRule
{
    private TypeNode _notImplementedException;
    private Member _currentMember;

    public DoNotRaiseNotImplementedException()
        : base("DoNotRaiseNotImplementedException",
               // The following string must be the assembly name (here
               // Bevonn.CodeAnalysis) followed by a dot and then the
               // metadata file name without the xml extension (here
               // DesignRules). See the note at the end for more details.
               "Bevonn.CodeAnalysis.DesignRules",
               typeof (DoNotRaiseNotImplementedException).Assembly) { }

    public override void BeforeAnalysis()
    {
        base.BeforeAnalysis();
        _notImplementedException = FrameworkAssemblies.Mscorlib.GetType(
            Identifier.For("System"),
            Identifier.For("NotImplementedException"));
    }

    public override ProblemCollection Check(Member member)
    {
        var method = member as Method;
        if (method != null)
        {
            _currentMember = member;
            VisitStatements(method.Body.Statements);
        }
        return Problems;
    }

    public override void VisitThrow(ThrowNode throwInstruction)
    {
        if (throwInstruction.Expression != null &&
            throwInstruction.Expression.Type.IsAssignableTo(_notImplementedException))
        {
            var problem = new Problem(
                GetResolution(),
                throwInstruction.SourceContext,
                _currentMember.Name.Name);
            Problems.Add(problem);
        }
    }
}

And this is the rule metadata:

<?xml version="1.0" encoding="utf-8" ?>
<Rules FriendlyName="Bevonn Design Rules">
  <Rule TypeName="DoNotRaiseNotImplementedException" Category="Bevonn.Design" CheckId="BCA0001">
    <Name>Do not raise NotImplementedException</Name>
    <Description>NotImplementedException should not be used in production code.</Description>
    <Url>http://stackoverflow.com/questions/410719/notimplementedexception-are-they-kidding-me</Url>
    <Resolution>Implement the method or property accessor.</Resolution>
    <MessageLevel Certainty="100">CriticalError</MessageLevel>
    <Email></Email>
    <FixCategories>NonBreaking</FixCategories>
    <Owner></Owner>
  </Rule>
</Rules>

To build this you need to:

  • reference Microsoft.FxCop.Sdk.dll and Microsoft.Cci.dll

  • Put the metadata in a file called DesignRules.xml and add it as an embedded resource to your assembly

  • Name your assembly Bevonn.CodeAnalysis. If you want to use different names for either the metadata or the assembly files, make sure you change the second parameter to the base constructor accordingly.

Then simply add the resulting assembly to your FxCop rules and take those damned exceptions out of your precious code. There are some corner cases where it won't report a NotImplementedException when one is thrown but I really think you are hopeless if you're actually writing such cthulhian code. For normal uses, i.e. throw new NotImplementedException();, it works, and that is all that matters.




回答2:


It's there to support a fairly common use case, a working but only partially completed API. Say I want to developers to test and evaluate my API - WashDishes() works, at least on my machine, but I haven't gotten around yet to coding up DryDishes(), let alone PutAwayDishes(). Rather than silently failing, or giving some cryptic error message, I can be quite clear about why DryDishes() doesn't work - I haven't implemented it yet.

Its sister exception NotSupportedException make sense mostly for provider models. Many dishwashers have a drying function, so belongs in the interface, but my discount dishwasher doesn't support it. I can let that be known via the NotSupportedException




回答3:


I'll summarize my views on this in one place, since they're scattered throughout a few comments:

  1. You use NotImplementedException to indicate that an interface member isn't yet implemented, but will be. You combine this with automated unit testing or QA testing to identify features which still need to be implemented.

  2. Once the feature is implemented, you remove the NotImplementedException. New unit tests are written for the feature to ensure that it works properly.

  3. NotSupportedException is generally used for providers that don't support features that don't make sense for specific types. In those cases, the specific types throw the exception, the clients catch them and handle them as appropriate.

  4. The reason that both NotImplementedException and NotSupportedException exist in the Framework is simple: the situations that lead to them are common, so it makes sense to define them in the Framework, so that developers don't have to keep redefining them. Also, it makes it easy for clients to know which exception to catch (especially in the context of a unit test). If you have to define your own exception, they have to figure out which exception to catch, which is at the very least a counter-productive time sink, and frequently incorrect.




回答4:


Why does the NotImplementedException exist?

NotImplementedException is a great way to say that something is not ready yet. Why it's not ready is a separate question for method's authors. In production code you're unlikely to catch this exception, but if you did you can immediately see what happened and it's much better than trying to figure out why methods was called but nothing happened or even worse - receive some "temporary" result and get "funny" side effects.

Is NotImplementedException the C# equivalent of Java's UnsupportedOperationException?

No, .NET has NotSupportedException

I have to run my algorithm, catch NotImplementedExceptions and the some how roll back my application to some sane state

Good API has XML methods documentation that describes possible exceptions.

I'm very suspicious of the NotSupportedException also... Not supported? What the? If it's not supported, why is it part of your interface?

There can be millions reasons. For example you can introduce new version of API and don't want to/can't support old methods. Again, it is much better to see descriptive exception rather then digging into documentation or debugging 3rd party code.




回答5:


The main use for a NotImplementedException exception is in generated stub code: that way you don't forget to implement it!! For example, Visual Studio will explicitly implement an interface's methods/properties with the body throwing a NotImplementedException.




回答6:


Re NotImplementedException - this serves a few uses; it provides a single exception that (for example) your unit tests can lock onto for incomplete work. But also, it really does do what is says: this simply isn't there (yet). For example, "mono" throws this all over the place for methods that exist in the MS libs, but haven't been written yet.

Re NotSupportedException - not everything is available. For example, many interfaces support a pair "can you do this?" / "do this". If the "can you do this?" returns false, it is perfectly reasonable for the "do this" to throw NotSupportedException. Examples might be IBindingList.SupportsSearching / IBindingList.Find() etc.




回答7:


Most developers at Microsoft are familiar with design patterns in which a NotImplementedException is appropriate. It's fairly common actually.

A good example is a Composite Pattern, where many objects can be treated as a single instance of an object. A component is used as a base abstract class for (properly) inherited leaf classes. For example, a File and Directory class may inherit from the same abstract base class, because they are very similar types. This way, they can be treated as a single object (which makes sense when you think about what files and directories are - in Unix for example, everything is a file).

So in this example, there would be a GetFiles() method for the Directory class, however, the File class would not implement this method, because it doesn't make sense to do so. Instead, you get a NotImplementedException , because a File does not have children the way a Directory does.

Note that this is not limited to .NET - you'll come across this pattern in many OO languages and platforms.




回答8:


Why do you feel the need to catch every possible exception? Do you wrap every method call with catch (NullReferenceException ex) too?

Stub code throwing NotImplementedException is a placeholder, if it makes it to release it should be bug just like NullReferenceException.




回答9:


I think there are many reasons why MS added NotImplementedException to the framework:

  • As a convenience; since many developers will need it during development, why should everybody have to roll their own?
  • So that tools can rely on its presence; for example, Visual Studio's "Implement Interface" command generate method stubs that throw NotImplementedException. If it were not in the framework, this would not be possible, or at least rather awkward (for example, it could generate code that doesn't compile until you add your own NotImplementedException)
  • To encourage a consistent "standard practice"

Frankodwyer thinks of NotImplementedException as a potential timebomb. I would say that any unfinished code is a timebomb, but NotImplementedException is much easier to disarm than the alternatives. For example, you could have your build server scan the source code for all uses of this class, and report them as warnings. If you want to be really ban it, you could even add a pre-commit hook to your source-control system that prevents checkin of such code.

Sure, if you roll your own NotImplementedException, you can remove it from the final build to make sure that no time bombs are left. But this will only work if you use your own implementation consistently in the entire team, and you must make sure that you don't forget to remove it before you release. Also, you might find that you can't remove it; maybe there are a few acceptable uses, for example in testing code that is not shipped to customers.




回答10:


There is really no reason to actually catch a NotImplementedException. When hit, it should kill your app, and do so very painfully. The only way to fix it is not by catching it, but changing your source code (either implementing the called method, or changing the calling code).




回答11:


Two reasons:

  1. Methods are stubbed out during development, and throw the exception to remind the developers that their code writing is not finished.

  2. Implementing a subclass interface that, by design, does not implement one or more methods of the inherited base class or interface. (Some interfaces are just too general.)




回答12:


This sounds like a potential minefield to me. In the distant past I once worked on a legacy network system that had been running nonstop for years and which fell over one day. When we tracked the problem down, we found some code that had clearly not been finished and which could never have worked - literally, like the programmer got interrupted during coding it. It was obvious that this particular code path had never been taken before.

Murphy's law says that something similar is just begging to happen in the case of NotImplementedException. Granted in these days of TDD etc, it should be picked up before release, and at least you can grep code for that exception before release, but still.

When testing it is difficult to guarantee coverage of every case, and this sounds like it makes your job harder by making run time issues of what could have been compile time issues. (I think a similar sort of 'technical debt' comes with systems that rely heavily on 'duck typing', while I acknowledge they are very useful).




回答13:


You need this exception for COM interop. It's E_NOTIMPL. The linked blog also shows other reasons




回答14:


Throwing NotImplementedException is the most logical way for the IDE to to generate compiling stub code. Like when you extend the interface and get Visual Studio to stub it for you.

If you did a bit of C++/COM, that existed there as well, except it was known as E_NOTIMPL.

There is a valid use case for it. If you are working on a particular method of an interface you want you code to compile so you can debug and test it. According to your logic you would need to remove the method off the interface and comment out non-compiling stub code. This is a very fundamentalist approach and whilst it has merit, not everyone will or should adhere to that. Besides, most of the time you want the interface to be complete.

Having a NotImplementedException nicely identifies which methods are not ready yet, at the end of the day it's as easy as pressing Ctrl+Shift+F to find them all, I am also sure that static code analysis tools will pick it up too.

You are not meant to ship code that has NotImplementedException exception. If you think that by not using it you can make your code better, go forth, but there are more productive things you can do to improve the source quality.




回答15:


NotImplementedException

The exception is thrown when a requested method or operation is not implemented.

Making this a single exception defined in the .NET core makes it easier to find and eradicate them. If every developer should create their own ACME.EmaNymton.NotImplementedException it would be harder to find all of them.

NotSupportedException

The exception is thrown when an invoked method is not supported.

For instance when there is an attempt to read, seek, or write to a stream that does not support the invoked functionality.

For instance generated iterators (using yield keyword) is-a IEnumerator, but the IEnumerator.Reset method throws NotSupportedException.




回答16:


From ECMA-335, the CLI specification, specificialy the CLI Library Types, System.NotImplementedException, remarks section:

"A number of the types and constructs, specified elsewhere in this Standard, are not required of CLI implementations that conform only to the Kernel Profile. For example, the floating-point feature set consists of the floating-point data types System.Single and System.Double. If support for these is omitted from an implementation, any attempt to reference a signature that includes the floating-point data types results in an exception of type System.NotImplementedException."

So, the exception is intended for implementations that implement only minimal conformance profiles. The minimum required profile is the Kernel Profile (see ECMA-335 4th edition - Partition IV, section 3), which includes the BCL, which is why the exception is included in the "core API", and not in some other location.

Using the exception to denote stubbed methods, or for designer generated methods lacking implementation is to misunderstand the intent of the exception.

As to why this information is NOT included in the MSDN documentation for MS's implementation of the CLI is beyond me.




回答17:


I can't vouch for NotImplementedException (I mostly agree with your view) but I've used NotSupportedException extensively in the core library we use at work. The DatabaseController, for example, allows you to create a database of any supported type then use the DatabaseController class throughout the rest of your code without caring too much about the type of database underneath. Fairly basic stuff, right? Where NotSupportedException comes in handy (and where I would have used my own implementation if one didn't already exist) is two main instances:

1) Migrating an application to a different database It's often argued this rarely, if ever, happens or is needed. Bullsh*t. Get out more.

2) Same database, different driver Most recent example of this was when a client who uses an Access-backed application upgraded from WinXP to Win7 x64. Being no 64-bit JET driver, their IT guy installed the AccessDatabaseEngine instead. When our app crashed, we could easily see from the log it was DB.Connect crashing with NotSupportedException - which we were quickly able to address. Another recent example was one of our programmers trying to use transactions on an Access database. Even though Access supports transactions, our library doesn't support Access transactions (for reasons outside the scope of this article). NotSupportedException, it's your time to shine!

3) Generic functions I can't think of a concise "from experience" example here but if you think about something like a function that adds an attachment to an email, you want it to be able to take a few common files like JPEGs, anything derived from various stream classes, and virtually anything which has a ".ToString" method. For the latter part, you certainly can't account for every possible type so you make it generic. When a user passes OurCrazyDataTypeForContainingProprietarySpreadsheetData, use reflection to test for the presence of a ToString method and return NotSupportedException to indicate lack of support for said data types that don't support ToString.

NotSupportedException isn't by any means a crucial feature but it's something I find myself using a lot more as I work on larger projects.




回答18:


Lets say you have this method in your production code

public void DoSomething()

Which one would you take if you want to leave it later to be finished?

public void DoSomething()
{
}

or

public void DoSomething()
{
    throw new NotImplementedException();
}

I would certainly take the second. Coupled with Elmah or whatever error logging mechanism you have (implemented as an aspect across your entire application). Together with log/exception filtering to trigger for critial error email notification when one is caught.

The argument that NotImplementedException == unfinished isn't correct either. (1) Catching of unimplemented methods should be left to unit tests/ integration tests. If you have 100% coverage (which you should now do, with so many many mock/stub/code generation tools) with no NotImplementedException, what are your worries? (2) Code generation. Plain simple. Again, if I generate the code, and only use half of the generated code, why wouldn't I have NotImplementedException in the rest of the generated stub?

It's like saying code shouldn't compile unless every nullable input should be checked/handled for null. (AKA the trillion dollar mistake, if not more). Language should be flexible, while tests/contracts should be solid.




回答19:


Rarely I do use it for interface fixing. Assume that you've an interface that you need to comply but certain method will be never called by anyone, so just stick a NotImplementedException and if someone calls it they will know they are doing something wrong.




回答20:


NotImplementedException is thrown for some method of .NET (see the parser C# in Code DOM which is not implemented, but the method exist !) You can verify with this method Microsoft.CSharp.CSharpCodeProvider.Parse




回答21:


They are both hacks for two common problems.

NotImplementedException is a workaround for developers who are architecture astronauts and like to write down the API first, code later. Obviously, since this is not a incremental process, you can't implement all at once and therefore you want to pretend you are semi-done by throwing NotImplementedException.

NotSupportedException is a hack around the limitation of the type systems like those found in C# and Java. In these type systems, you say that a Rectangle 'is a' Shape iff Rectangle inherits all of Shapes characteristics (incl. member functions + variables). However, in practice, this is not true. For example, a Square is a Rectangle, but a Square is a restriction of a Rectangle, not a generalization.

So when you want to inherit and restrict the behavior of the parent class, you throw NotSupported on methods which do not make sense for the restriction.




回答22:


What about prototypes or unfinished projects?

I don't think this is a really bad idea to use an exception (although I use a messagebox in that case).




回答23:


Well, I somewhat agree. If an interface has been made in such a way that not all class can implement all bits of it, it should've been broken down in my opinion.

If IList can or cannot be modified, it should've been broken down into two, one for the unmodifiable part (getters, lookup, etc.), and one for the modifiable part (setters, add, remove, etc.).




回答24:


I have a few NotImplementedExceptions in my code. Often times it comes from part of an interface or abstract class. Some methods I feel I may need in the future, they make sense as being part of the class, but I just don't want to take the time to add unless I actually need it. For example, I have an interface for all the individual kinds of stats in my game. One of those kinds are a ModStat, which is the sum of the base stat plus all the modifiers (ie weapons, armor, spells). My stat interface has an OnChanged event, but my ModStat works by calculating the sum of all stats it references each time it is called. So instead of having the overhead of a ton of ModStat.OnChange events being raised every time a stat changes, I just have a NotImplementedException thrown if anyone tries to add/remove a listener to OnChange.

.NET languages are all about productivity, so why spend your time coding something you won't even use?




回答25:


Here is one example: In Java, whenever you implement the interface Iterator, you have to override the obvious methods hasNext() and next(), but there is also delete(). In 99% of the usecases I have I do not need this, so I just throw a NotImplementedException. This is much better than silently doing nothing.




回答26:


The NotImplementedException exists only to facilitate development. Imagine you start implementing an interface. You'd like to be able to at least build when you are done implementing one method, before moving to the next. Stubbing the NotImplemented methods with NotImplementedExceptions is a great way of living unfinished code that is super easy to spot later. Otherwise you would run the risk of quickly implementing something that you might forget to fix.




回答27:


If you don't want to use it then just ignore it. If you have a block of code whose success depends on every piece of it succeeding, but it might fail in between, then your only option is to catch the base Exception and roll back what needs to be rolled back. Forget NotImplementedException. There could be tons of exceptions thrown, like MyRandomException and GtfoException and OmgLolException. After you originally write the code I could come by and throw ANOTHER exception type from the API you're calling. One that didn't exist when you wrote your code. Handle the ones you know how to handle and rollback for any others i.e., catch(Exception). It's pretty simple, I think... I find it comes in handy too. Especially when you're trying fancy things with the language/framework that occasionally force things upon you.

One example I have is serialization. I have added properties in my .NET library that don't exist in the database (for example, convenient wrappers over existing "dumb" properties, like a FullName property that combines FirstName, MiddleName, and LastName). Then I want to serialize these data types to XML to send them over the wire (for example, from an ASP.NET application to JavaScript), but the serialization framework only serializes public properties with both get and set accessors. I don't want you to be able to set FullName because then I'd have to parse it out and there might be some unforeseen format that I wrongly parse and data integrity goes out the window. It's easier to just use the underlying properties for that, but since the language and API require me to have a set accessor, I'll throw a NotImplementedException (I wasn't aware of NotSupportedException until I read this thread, but either one works) so that if some programmer down the road does try to set FullName he'll encounter the exception during testing and realize his mistake.



来源:https://stackoverflow.com/questions/410719/why-does-notimplementedexception-exist

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!