The best explanation I have so far for this is "magic".
public string GetRouteSegmentData(RouteSegment RouteSegment, Exporter.RouteExporter Exporter)
{
try
{
List<RouteProviderSegmentData> List = Provider.GetSegments(RouteSegment);
}
catch (Exception e)
{
// logging and return null
}
}
// -----------------
// In the Provider class (more accurately, a child of a Provider class)
public override List<RouteProviderSegmentData> GetSegments(RouteSegment RouteSegment)
{
// CHECK 1
if (RouteSegment.RouteLineEntity == null) { throw new Exception("LineEntity null for route " + RouteSegment.Code); }
// CHECK 2
if (RouteSegment.RouteLineEntity.ListRouteLineParts == null) { throw new Exception("LineParts null for route " + RouteSegment.Code); }
// ...
}
So this is what happens: CHECK 1 is true, RouteLineEntity is in fact null, and when I debug it nicely steps into the "throw" part. But then... nothing seems to happen with that. The catch in GetRouteSegmentData() doesn't catch anything, it's like nothing was ever thrown. GetSegments() simply continues on to CHECK 2, and since RouteLineEntity is still null, this throws an exception (because I'm trying to access the ListRouteLineParts property of an object that's null), and this time that exception DOES get caught in GetRouteSegmentData().
So for some reason my manually thrown exception is blatantly ignored.
I've tried to put some code behind that first thrown, but this is never executed (as you'd expect, I guess).
What's going on here?
Related
Is it alright to return an empty object in case of an exception or should we throw the exception so that caller may know what has gone wrong?
public async Task<UserInfoModel> GetUserInfoByRole(Role role)
{
UserModel userInfo = new UserModel();
try
{
// do something
}
catch (Exception ex)
{
// do logging
// throw;
}
return userInfo;
}
It depends if you are creating a class, component, ... for others to use, you obviously should throw an exception. because they need to know about it and handle the exception the way that suits them.
If it is a method in your own code, may be returning a null value would be sufficient, because you might just check the return value and if it is null you know that there was an error and you don't want to program break because of the exception, otherwise you will need another exception handling again.
I'm writing a function that takes user input, runs a procedure in our database, and compares the values. Along the way, I need to check that we've received proper input and then that the query has returned an acceptable value.
private void DoTheThing(int? userInput1, int? userInput2, int valuePassedIn)
{
if (userInput1 == null || userInput2 == null)
{
Exception ex = new Exception();
ex.Data.Add("Message", "You screwed up.");
throw ex;
}
var queryResult = 0; //execute a query using the non-null inputs
if (queryResult == null) //or otherwise doesn't return an acceptable value
{
Exception ex = new Exception();
ex.Data.Add("Message", "some other thing happened");
throw ex;
}
else
{
//We're good, so do the thing
}
}
A quick note about this: I'm aware of the argument against exceptions as flow control and that I'd be better off checking the user's input before I even get this far. I won't get into all the details, but please accept that I'm kind of stuck writing the function this way.
That having been said, here's my question:
Given that the only differences between the 2 exceptions here is the message and the time at which they are thrown, how can I clean this code up to be both DRY and avoid running unnecessary code after determining that there will be a problem?
I thought about using a goto and placing the error code there, but that really only moves the problem around. If I move the exception code to the bottom and check for a message variable (or something similar), then I'm just running code that doesn't need to be run in the first place.
I suggest not throwing Exception (which means something went wrong, no comments are available), but ArgumentNullException and InvalidOperationException classes. Another amendment is avoding arrow-head
antipattern:
private void DoTheThing(int? userInput1, int? userInput2, int valuePassedIn)
{
// What actually went wrong? An argument "userInput1" is null
if (null == userInput1)
throw new ArgumentNullException("userInput1");
else if (null == userInput2)
throw new ArgumentNullException("userInput2"); // ...or userInput2 is null
var queryResult = executeSomeQuery(userInput1, userInput2, valuePassedIn);
// What went wrong? We don't expect that null can be returned;
// so the operation "executeSomeQuery" failed:
// we've provided validated (not null) values and got unexpected return.
// Let it have been known.
if (null == queryResult)
throw new InvalidOperationException(
String.Format("Query ({0}, {1}, {2}) returned null when bla-bla-bla expected",
userInput1, userInput2, valuePassedIn));
// We're good, so do the thing
// Note that's there's no "arrow-head antipattern":
// we're not within any "if" or "else" scope
}
Edit: Since every *Exception is inherited from Exception you can put some info into Data:
Exception ex = new ArgumentNullException("userInput1");
ex.Data.Add("Some key", "Some value");
throw ex;
but often Message is a far better place to explain what had heppened.
You might be better off creating a BadInputException class and a NullQueryResultException class. These do two different things and throwing a specific exception is better than throwing a generic Exception(...). In fact I think FXCop or Visual Studio's Code Analysis will give you a warning about throwing generic Exceptions.
It's not really all that much new code to write.
public class BadInputException : Exception
{
public BadInputException()
{
this.Data.Add("Message", "You screwed up.")
}
}
Then instead of this:
Exception ex = new Exception();
ex.Data.Add("Message", "You screwed up.");
throw ex;
Do this:
throw new BadInputException();
Edit: moved the "You screwed up" message from the Message property to the Data collection to match what the OP wants.
I would create a method:
private void CheckResult(bool cond, string msg, string info) {
if (!cond)
return;
Exception ex = new Exception();
ex.Data.Add(msg, info);
throw ex;
}
and call
CheckResult(userInput1 == null || userInput2 == null, "Message", "You screwed up.");
and
CheckResult(queryResult == null, "Message", "You screwed up.");
I think the QuestionRefactoring Guard Clauses is helpful for you .
There are something about this in Replace Nested Conditional with Guard Clauses.
Hope it's useful.
What's the right way to treat and test flow control on methods that are void if not with exceptions? I've seen that Microsoft do not recomend such practice so what's the right way?
This is how how I'm treating parameters that shouldn't be accepted in my method:
public void RentOutCar(ReservationInfo reservationInfo)
{
try
{
if (string.IsNullOrEmpty(reservationInfo.ReservationNumber) || string.IsNullOrWhiteSpace(reservationInfo.ReservationNumber))
{
throw new ArgumentException("Reservation Number is null or empty.");
}
if (reservationInfo == null)
{
throw new ArgumentNullException("Null Reservation info.");
}
if (reservationInfo.Car == null)
{
throw new ArgumentNullException("No car registered to rent.");
}
if (reservationInfo.RentalDatetime == DateTime.MinValue || reservationInfo.RentalDatetime == DateTime.MaxValue)
{
throw new ArgumentException("Rental Date has an unreal value.");
}
if (reservationInfo.Car.Mileage <0)
{
throw new ArgumentOutOfRangeException("Mileage can't be less than 0.");
}
reserverationsRegister.ReservationsDone.Add(reservationInfo);
}
catch (Exception)
{
throw;
}
}
This is not what Microsoft mean when they say you should not control flow with exceptions.
While the use of exception handlers to catch errors and other events
that disrupt program execution is a good practice, the use of
exception handler as part of the regular program execution logic can
be expensive and should be avoided.
In other words, you should not throw (and subsequently catch) exceptions in situations where the code in the try block is likely to throw and represents legitimate program logic.
A contrived example of controlling flow with exceptions may look like:
int x = GetUserInput();
try
{
MustAcceptPositiveInput(x);
}
catch (InputIsNonPositiveException)
{
MustAcceptNonPositiveInput(x);
}
The equivalent 'correct' code may look like:
int x = GetUserInput();
if (x > 0)
{
MustAcceptPositiveInput(x);
}
else
{
MustAcceptNonPositiveInput(x);
}
Exceptions should be reserved for exceptional situations, those which are not part of expected program execution. It results in more readable, less surprising and more performant code.
What you are doing in your code is fine (except for the redundant try-catch and faulty order of tests as #Clay mentions), you are validating inputs for exceptional values, those which your code was not meant to handle.
Throwing an exception if the inputs are not valid is fine. Test reservationInfo for null first - or your other tests will break in unexpected ways. Also - no point in wrapping your tests in a try/catch if all you're going to do is rethrow it.
This is not a "control flow" issue as described in the article you put in the comments - and throwing exceptions is appropriate here.
You might consider wrapping just the "working code" in a try/catch, but only if you can recover from (or maybe log) any exceptions:
try
{
reserverationsRegister.ReservationsDone.Add(reservationInfo);
}
catch( Exception ex )
{
LogError( ex );
throw;
}
Using MODI (Microsoft Office Document Imaging) OCR, sometimes the image doesn't contain any text. Therefore doc.OCR throws an exception.
public static string recognize(string filepath, MODI.MiLANGUAGES language = MODI.MiLANGUAGES.miLANG_RUSSIAN, bool straightenimage = true)
{
if (!File.Exists(filepath)) return "error 1: File does not exist";
MODI.Document doc = new MODI.Document();
doc.Create(filepath);
try
{
doc.OCR(language, false, false);
}
catch
{
//
}
MODI.Image image = (MODI.Image)doc.Images[0];
string result="";
foreach (MODI.Word worditems in image.Layout.Words)
{
result += worditems.Text + ' ';
if (worditems.Text[worditems.Text.Length - 1] == '?') break;
}
doc.Close(false);
System.Runtime.InteropServices.Marshal.ReleaseComObject(doc);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(doc);
System.Runtime.InteropServices.Marshal.ReleaseComObject(image);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(image);
image = null;
doc = null;
GC.Collect();
GC.WaitForPendingFinalizers();
return result;
}
This code terminates the application, not what I need :(
How do I just make it fade away like nothing happened?
You are 95% of the way there with the code you posted:
try
{
doc.OCR(language, false, false);
}
catch
{
// Here you would check the exception details
// and decide if this is an exception you need
// and want to handle or if it is an "acceptable"
// error - at which point you could popup a message
// box, write a log or doing something else
}
That said it would be prudent to catch the exception type that occurs when the document is empty and then have a different exception handler for any other errors that may occur
try
{
doc.OCR(language, false, false);
}
catch (DocumentEmptyException dex)
{
}
catch
{
}
DocumentEmptyException is, I assume, not the exception type thrown - if you look at the docs for the OCR method (or via debug) you will be able to work out which exception type to catch
EDIT (After seeing your edit)
Are you sure the exception is being thrown from the doc.OCR(...) method? In your edit you added additional code after the catch, could it be coming from there instead?
For example, the line after the catch:
MODI.Image image = (MODI.Image)doc.Images[0];
If your document is empty and therefore the exception is thrown and ignored (as the catch block has nothing in it), does this line continue to work?
You are doing nothing in the catch block, just swallowing the exception which is very bad. The code continues to execute and you try to use the doc variable but because the .OCR call has failed it is more than possible that another exception is thrown later. For example doc.Images[0] will probably crash if the OCR has failed. So either terminate the execution of the method by returning something or put the entire method in a try/catch block.
So, I have a list containing a custom class, MyClass
MyClass has properties, which can be null (but aren't meant to be).
When this class is sorted, using a custom sorter, where the sorter accesses this null property and throws an exception, the exception is considered unhandled, even though there is a try-catch block around the sort method.
Now for some reason the exception still gets written to the console, which is what the exception handler is doing.
I have a real application with this same issue, causing my unit tests to fail, even though the exception is handled correctly and I cannot explain this.
So I have attached some sample code to explain myself better, run this from VS.
Updated Code
Results:
System.InvalidOperationException
Failed to compare two elements in the array.
Done!
So it seems to be handling my custom exception, and throwing its own?
using System;
using System.Collections.Generic;
using System.Data;
namespace TestSortException
{
class Program
{
static void Main()
{
try
{
var list = new List<MyClass>
{
new MyClass("1"),
new MyClass(null),
new MyClass("fdsfsdf")
};
list.Sort(new MyClassSorter());
}
catch(Exception e)
{
Console.WriteLine(e.GetType());
Console.WriteLine(e.Message);
}
Console.WriteLine("Done!");
Console.ReadLine();
}
}
class MyClassSorter : IComparer<MyClass>
{
public int Compare(MyClass x, MyClass y)
{
// try
// {
if (x.MyString == y.MyString)
return 0;
// Unhandled??? Exception here
if (x.MyString.Length > y.MyString.Length)
return 1;
return -1;
// }
// catch (Exception)
// {
// return -1;
// }
}
}
class MyClass
{
private string _myString;
public string MyString
{
get
{
if (_myString == null) throw new DataException("MyString is Null");
return _myString;
}
}
public MyClass(string myString)
{
_myString = myString;
}
}
}
There's a try/catch block round the Sort method, yes - and that catch block catches the exception. In other words, Sort throws an exception and your catch block catches it. It doesn't propagate out beyond Main - so "Done!" is printed.
This is exactly what I'd expect. In what way is it "unhandled" in your experience? Were you expecting Sort not to throw the exception? It needs to do something to indicate the failure to compare two elements, and this seems to be the most appropriate course of action.
In what way are your unit tests failing? Are you deliberately giving them invalid data? How do you want your comparison code to react to invalid data? If it should ignore it (and return a comparison based on another property), then you should actively check the property rather than letting an exception propagate. In most cases I'd rather allow the exception if this indicates that there's a bug earlier on though.
EDIT: Based on your other comments, it sounds like you're doing the appropriate thing, letting the exception bubble up - but it's not clear in what way you're seeing the exception not be handled.
If you're running in the debugger, it may be breaking on the exception being thrown, but that doesn't mean it won't be handled. Try either changing your exception settings or running without the debugger.
EDIT: Yes, Sort will catch the exception and throw an InvalidOperationException instead - but you can use the InnerException property of that exception to get hold of the original one. It's unfortunate that the documentation doesn't specify this :(
For example, when it checks that string "1" isn't equal to null. But it wants then to compare lengths of "1" string and null => which is impossible.
I assume you work with .Net Framework 4.0. The new thing there is that a NullRefenrenceException can not be caught any more (similar to OutOfMemory exception).