String.Format mistyping parameters - c#

This application tests hardware and prints the results of the test to the console. Multiple devices can be under test at once so I have multiple threads and locking around access to the console, both input and output. So I originally had this in my code right before passing the result to the function that prints:
string message = String.Format("The DUT is: {0}. The total test " +
"was a : {2}.", MAC, testResultString);
The 2 caused the application to stop executing that function. It switched control back to the other threads but never complained about an error etc so the problem took quite a while to track down. What are good strategies/best practices for dealing with String.Format since it is apparently pretty quiet when there is a problem. Or alternatives to string format that have similar flexibility.
Edit: yes the bug was tracked down and the code changed to:
string message = String.Format("The DUT is: {0}. The total test " +
"was a : {1}.", MAC, testResultString);
The point of the question is moreso how to deal with String.Format silently failing. As correctly pointed out by #alexd, this is not a problem specific to String.Format. Any function in a separate thread that throws an exception will have the same issue.
Thanks for the pointers on Re-sharper and the edits #VirtualBlackFox.

As Daniel James Bryars already said, meet ReSharper:
2 Warnings on this line as the second parameter is never used in the format string (And one error due to missing ;).
You can even with an attribute mark your own code or external code like NLog with this feature.
Warning are aggregated on the scrollbar as colored lines, available on a separate window and it can be integrated in nearly any automated system (Sonar for example)

The problem is not specific to String.Format. Pretty much any exception, thrown from a background thread, will lead to the same problem.
You may consider AppDomain.UnhandledException to catch and report such exceptions:
AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
{
Exception x = (Exception)e.ExceptionObject;
// report error, etc.
};
But there are quite some details to be aware of, see http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception%28v=vs.110%29.aspx.
P.S. This page provides a good overview of possibilities:
WPF global exception handler

This will throw an error because {2} actually refers to the third parameter after the string. Since you only have two, it throws an exception.
string message = String.Format("The DUT is: {0}. The total test " +
"was a : {1}.", MAC, testResultString);
As long as your token references don't exceed your parameter count, you should not have to worry about error handling on a String.Format.

Why donĀ“t you try something like:
string message = String.Format("The DUT is: {0}. The total test was a : {1}.", MAC, testResultString);
I hope this helps! And SLaks says in the comment! Add a try/catch to check the exceptions ;)

If your using VS then you may need to enable those exceptions under the debug menu. String.Format does throw an exception if the number of arguments is less than any index used. Look at the MSDN page.
Update: more specifically, you need to enable exceptions from the CLR (Common Language Runtime).

In C#6 you can now use "String interpolation" (see here and here) and do something this:
string message = $"The DUT is: {MAC}. The total test " +
"was a : {testResultString}.";
and I don't know if this is compile time checked.

Related

Tracking actions taken on an object - proven way?

Let's face it, some of the time you can get away with simply tracking exceptions and reporting on those when something fails, but most of the time when you're performing complex operations and working against a library that you did not build, you have to keep track of everything that is happening yourself so that if something goes wrong, you can report on it properly. Otherwise, you can have some strange errors come up like: "String cannot be empty" with no more information than that... yet in your code, there could be thousands of lines of code where this error could come up, which would make troubleshooting this error a complete nightmare, not to mention reporting the correct verbose information to the user nearly impossible!
Let's take a small example off the top of my head where this would apply... Say you are building an application that takes developer settings for IIS from their dev station, and applying them over to a server somewhere using Microsoft.Web.Administration. This would involve multiple objects like Site, ApplicationPool, Application, VirtualDirectory, etc... that can contain multiple property values.
Once on the server, you have to take every property value the developer has set and apply them to the actual server, and any one of those actions could fail for one reason or another.
In order to track the progress and/or failures for proper reporting, you will have to implement your own code because the Microsoft.Web.Administration library sadly does not provide a lot of details in its exception messages...
The way I've always done this is to keep a local log in the "Apply Settings/Front-end" routine and then use this to know where the code was at when something failed... something like this:
try
{
this.log.Add("Applying pool.Failure.AutoShutdownExe");
pool.Failure.AutoShutdownExe = this.deployment.WebSite.VirtualDirectory.ApplicationPool.AutoShutdownExe;
this.log.Add("Successfully applied pool.Failure.AutoShutdownExe");
//.........
}
catch(exception ex)
{
this.log.Add("Deploy failure! Fatal error occurred. " + Environment.Newline +
"Type: " + ex.GetType().Name + Environment.Newline +
"Message: " + ex.Messsage + Environment.Newline +
"Stack Trace: " + Environment.Newline + ex.StackTrace);
//.................
}
Which results, in the case of failure at the point demonstrated above, in a great and easy to read log like this:
- Deployment starting...
- .....
- .....
- Applying pool.Failure.AutoShutdownExe
- Deploy failure! Fatal error occurred.
Type: ArgumentNullException
Message: String cannot be empty
Stack Trace:
......... Line 35.. .
This works great because I can easily see where it failed, but I feel like I spend most of my time writing these logging entries rather than actually coding the functionality itself and I am wondering if there is an easier way to do this? Like moving this tracking functionality to the "Objects" themselves by making them "Self Aware Objects" that track their last accessed property which can then be used to report on later or something?
So what do you usually do?
- Don't verbose track and just blurt out the error and that's it?
- Verbose track in a way similar to what I'm doing above?
- Something completely different?
Is there a standard and proven way of doing this that takes the burden off the developer in any way?

detecting specific argument exceptions?

I need to catch a specific ArgumentException.
System.ArgumentException: Input array is longer than the number of
columns in this table.
I noticed that there are a number of ArugmentExceptions that can occur, but how would I go about catching this one specifically? "Input array is longer than the number of columns in this table"
unfortunately doing catch(ArgumentException ex) is not specific enough...
We are uploading a tab delimited file and the exception above tells us to tell the user to check the number of columns in the file and to try again.
Don't catch the exception - avoid it happening in the first place. You have the input, so you know how many columns have been provided. You know the table you're adding the data to, so you know how many columns are available.
You can - and should check the validity of the data before you try to add the rows. It's as simple as that.
ArgumentException should almost never be caught and "handled". It should be an indication of the caller providing a bad argument that could have been verified beforehand. That's a programming problem, and should be fixed by adding appropriate code on the calling side.
You will have to parse/analyse the exception message, because there is no extra information available. ArgumentExceptions are typically not meant to be caught, because they indicate a programming error. That's why there's no extra information.
Note that parsing the exception message can be error prone, since your application might be rolled out to Windows machines with a different culture. In that case the .NET version might throw localized exception messages.
You'll have to catch the ArgumentException, inspect it, and if it's not the one that interests you, re-throw it.
catch(ArgumentException ex) {
if(ex.ParamName!="specificargument" || ex.Message != "Input array is longer than the number of columns in this table")
throw;
//Handle exception, inform user
}
(Different checks may be more appropriate - I.e. it may not be appropriate to check the entire message text)
It would be better if the checks for the specific type could be performed without having to re-throw exceptions that don't match - and that's exactly what exception filters were invented for. Unfortunately, C# has never surfaced this feature (despite it existing in IL, and even exposed in VB.Net)

Getting line number of code

Within the code I'm responsible for, I have a few 'throw new Exception()' methods flying around.
The issue is, the catch is not always in the best place or even in the same class. This means when I catch an error, I don't know where the throw originated or even if I do, there could be hundreds/thousands of lines of code in each class.
So, within the throw message, for debugging, it may be useful to state the Class Name, Project Name, Method Name and the line number for easier navigation. The line number is tricky. I can't hard code it because as soon as I amend the code it's unlikely to remain on the same line.
So, my 2 questions are
1) Do we like this idea or think no, there are better approaches!
2) Any ideas how to get the line number?
Have you considered looking at the StackTrace information found under System.Diagnostics? An example can be found at:
http://msdn.microsoft.com/en-us/library/system.diagnostics.stacktrace.aspx
If you include the debugging symbols (.pdb) files, in the same directory as the .dll or .exe, it should load them automatically and provide the line number in the exception.StackTrace.
To build the symbols, in your release build settings, under Advanced Build Settings, turn Debug Info to Full
Look at the System.Diagnostics.StackFrame class for grabbing line numbers. I believe the method GetFileLineNumber may help you out
http://msdn.microsoft.com/en-us/library/system.diagnostics.stackframe
This info is usually available in the stack trace - By Jeremy (see my comments).
Sorry, not sure how to mark a comment as the right answer!?
Line numbers do not show up in code compiled in Release mode. If this is an in-house application you and you really want the line numbers you could always deploy the code compiled in Debug mode and then deploy the PDB's with the assemblies. But there is a performance cost involved in this as well so this is not always the best approach. I am not sure of any better approach at this point though.
If I remember correctly, the Roslyn project gives us a better way to get line numbers but not familiar enough with it to give more details.
You can capture the line number of a caller using C# 5.0 feature combined with default parameters. So instead of constructing and throwing the exception directly, make a method that constructs your exception.
Exception CreateMyException(
[CallerFilePath] string filePath = "",
[CallerMemberName] string memberName = "",
[CallerLineNumber] int lineNumber = 0)
{
return new Exception(string.Format("Exception thrown from line {0} in member {1} in file {2}",
lineNumber, memberName, filePath));
}
...elsewhere in your code...
throw CreateMyException(); // compiler injects current values for defaulted arguments.

bad performance from too many caught errors?

I have a large project in C# (.NET 2.0) which contains very large chunks of code generated by SubSonic. Is a try-catch like this causing a horrible performance hit?
for (int x = 0; x < identifiers.Count; x++)
{decimal target = 0;
try
{
target = Convert.ToDecimal(assets[x + identifiers.Count * 2]); // target %
}
catch { targetEmpty = true; }}
What is happening is if the given field that is being passed in is not something that can be converted to a decimal it sets a flag which is then used further along in the record to determine something else.
The problem is that the application is literally throwing 10s of thousands of exceptions as I am parsing through 30k records. The process as a whole takes almost 10 minutes for everything and my overall task is to improve that time some and this seemed like easy hanging fruit if its a bad design idea.
Any thoughts would be helpful (be kind, its been a miserable day)
thanks,
Chris
Using exceptions for control flow is generally a bad practice (exactly because of the poor efficiency that you're observing). What type of data do you need to convert to decimal? Could you use TryParse method or some other method that doesn't throw exception if the input is not in the expected format?
Decimal.TryParse method should do the trick if you're parsing strings as it reports failure by returnning false:
decimal d;
if (Decimal.TryParse(str, out d))
// Ok, use decimal 'd'
else
// Failed - do something else
That is a truly horrible looking piece of code. In general exceptions should only be used to capture unexpected results. The fact that you are getting lots of exceptions means that this is a common condition that should become part of the intrinsic logic.
decimal.TryParse would be a far better option here and I would suggest caching the value of identifiers.Count * 2 as well (not sure if compiler will optimise that)
There's a TryParse for Decimal as well. It avoids the exception and uses a bool instead to signal success/failure.
It's scary looking code, and you're getting good suggestions on how to fix it.
If you want to know if those exceptions are costing you a big percentage of time, there's a simple way to find out.
Just pause it about 10 times, and each time examine the call stack. If the exceptions are costing some percentage of time like, say, 50%, then you will see it in the process of throwing or catching them on roughly that percent of pauses.

format string- compile time checking

Is there any way to check the format string at compile time ?
Example:
Console.WriteLine("{0} is a really {1} site", "stackoverflow.com", "cool");//this will run
//this will give an exception as only one argument is supplied
Console.WriteLine("{0} is a really {1} site", "stackoverflow.com");
Exception:"Index (zero based) must be greater than or equal to zero and less than the size of the argument list."
and if format string is not in the correct format (i.e. missing the "}" after 1 here )
Console.WriteLine("{0} is a really {1 site", "stackoverflow.com","cool");
Exception: Input string was not in a correct format.
No, you can't add compile-time verification here. This is one of the down-sides to resource strings and formatting strings. You can do a few things to mitigate your problem.
Thoroughly unit test your public interfaces to be confident that your strings are being formatted correctly.
Use tools like ReSharper that can perform static analysis and let you know about these problems before you run your application.
Things are better threes.
While not really compile-time checking, ReSharper can warn you in Visual Studio when the number of arguments is wrong or the format string is in the wrong format.
No, there is no way to do this. Unit testing solves this problem.

Categories

Resources