开发者

How to avoid exception driven programming on "connect/disconnect" methods

I know that exception driven programming is something that shouldn't be done (and I imagine why). I'm building a library where I have to estabilish a connection with a device, so the programmer will call MyDeviceInstance.Connect on some point and now is where my problem shows up.

I wrote my connect methods as void Connect(), so I'm not returning anything (because actually I don't need anything), but I will throw exception in a lot of situations:

  1. If connection already exists
  2. If there are some wrong settings in MyDeviceInstance
  3. If my interop method deviceConnect will fail (and here is the biggest problem, because it will returns an int that represents a lot of errors)

Should Connect returns a boolean instead of void?There will be a lot of possibilities that I'll throw an exception.

The second part of this question is on another method, called void Update(). This method can works only if MyDeviceInstance is already connected. In this case I'll throw exceptions when:

  1. Connection doesn't exist
  2. Connection is lost for any reason (and the programmer will not expect this will happen, 开发者_运维技巧but can)
  3. Other interop errors

Should update returns a bool value instead of throwing all those exceptions (at least, to limit common errors like "connection doesn't exist")?

Thanks for any answer

EDIT 1:

I have to be more precise on one point: because we are talking about an USB device, when I'll call my method Update, this method could fail depending on the device (if is connected or not). More important, if I reconnect the device the interop method will start working again (and the normal method will do the same), without needing a reconnection or things like that (I don't know how this is working internally).

For update methods, should I throw if the device is disconnected? Programmatically speaking this is an exception, but user-speaking this will be a quite-normal situation.


Use exceptions for exceptional circumstances. So how do you know that you have an exceptional circumstance? It does depend on context of course and there are no hard and fast rules about it. Note that exceptions are heavy-weight, and you should not be using them for normal flow in your application.

In the instances that you mention, most seem to warrant exceptions.

For Connect, a connection already existing may not be an exceptional situation. You may want to make it idempotent if you want. Interop deviceConnect failing is definitely an exceptional situation. Something you did not expect. You can raise exceptions here, probably mapping the exit codes to meaningful exceptions.

For Update, connection doesn't exist is probably an exceptional circumstance and you can raise an exception. Also, connection lost is exceptional. Like this you can evaluate your situations.

Also, you can look at returning an int that is actually the error, rather than a boolean.


Exceptions should be exceptional and should not be used for flow control.

Depending on your app, if the connection already exists, you could choose to be passive an return successfully.

If there's incorrect settings, that's exceptional and should throw an exception.

Concerning the interop and connect, if you return bool, you have to ask yourself if consumers will have to handle and act differently based on the different error cases. There's two models - if you return bool, you may need to return other info (as out) if consumers need to handle cases differently. Handling error conditions should also not be based on string messages - you need some structured data like an exception type or error code.

On the Update call ...

If connection does't exist, you should throw an invalidOperationException since that's a programming error.

On connection post and interop errors, it goes back to the two patterns I discussed above. If consumers need to handle different error cases you can either return bool with other info or throw.

Personally, I prefer to have less exceptions thrown and limit them to programming errors or truly exceptional cases. For example, if you save an entity that violate a business rule is that an exception? You could argue that but I would argue that it's not exceptional for someone to fill out a form and enter something that doesn't meet the rules in code - that's not exceptional.

A good rule of thumb is I like to attach a debugger with break on exception and under normal use, nothing should be thrown. It should run clean.

Here's another SO post on exceptions:

Trying to understand exceptions in C#


Exceptions are exactly the right thing to use in this situation.

  1. Exceptions indicate something exceptional happened. In general you expect the connection to succeed so a failure to connect indicates an exceptional event.

  2. Exceptions can provide rich information about why the call failed.

  3. You can't ignore an exception (well you have to be deliberate about it). When the action requested represents an invalid request, it's easy for the calling method to just ignore it and continue abusing the connection. An exception forces the caller to deal with the problem.

The primary argument against using exceptions generally revolves performance. Which can be an issue if you're using exceptions for all error passing. However, when the action you are performing should typically succeed, an exception will not have any affect on performance.


If the code which calls a method will be prepared to deal with unusual results, the method should indicate unusual results via some means other than exceptions. If the calling code will not be prepared to deal with unusual results, then such results should cause exceptions. Unfortunately, there's no way for a class to magically know whether the caller is going to expect unusual results unless the caller tells it somehow. A common pattern in .net is for a class to provide pairs of "DoSomething" and "TryDoSomething" methods:

ResultType DoSomething();
Boolean TryDoSomething(ref ResultType result);

Frankly, I think the latter formulation would be better expressed as:

ResultType TryDoSomething(ref Boolean ok);

or perhaps:

ResultType TryDoSomething(ref Exception ex);

where "ex", if non-null, would indicate that an exception (ex) would have been thrown by DoSomething (but with a blank stack trace, since the exception won't actually have been thrown). Another pattern in some cases may be:

ResultType TryDoSomething(Action failureAction);

If an unexpected situation arises, the code will call the indicated delegate, with a parameter providing details of the context where the situation arose. That delegate may be able to allow for better error handling and recovery than would otherwise be possible, since it could be called before TryDoSomething gave up on whatever it was doing. For example, it could direct TryDoSomething() to keep retrying the operation unless or until the object supplying the delegate receives a cancel request.


if your Connect/Update methods can fail, then by all means return a bool for failure/success. you can also add an error code and/or error message methods/properties to your class that the programmer can access if he/she needs to.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜