0

Disclaimer This question is about, If and How we can use the Parse method exceptions, to find which argument/variable had actually failed the conversion. It is NOT, to argue if this is best or the correct way neither to find alternatives such as TryParse or subsequent If statements. However, each and every alternative or workaround is appreciated.

I have the following code-block in C#

string a = "1"
string b = "b"
string c = "3"

// add many more similar

try 
{
    int a1 = int.Parse(a);
    int b1 = int.Parse(b);
    int c1 = int.Parse(c);
}
catch (Exception e)
{
    // Here I will do some logging
}

Here the int b1 = int.Parse(b); line will fail and catch block will catch the exception.

Is it possible by examining, programmatically, the Exception info, to find the actual value (the value of string b, not the name of the variable) that caused the error. For example I would like to get something like:

Could not parse "b"

Athafoud
  • 2,898
  • 3
  • 40
  • 58
  • I'd solve it with `TryParse` - what's the problem with that approach? – fubo Dec 07 '16 at 13:32
  • 2
    `TryParse` is not a "workaround" but the only solid approach – Tim Schmelter Dec 07 '16 at 13:32
  • @fubo, There is not a problem with `TryParse`, I just looking for alternatives – Athafoud Dec 07 '16 at 13:33
  • 1
    Another option is to actually split that into multiple `try-catch` blocks so you know exactly what was failing, but I really don't see the point in avoiding `TryParse` here. – juharr Dec 07 '16 at 13:33
  • 2
    I think he wants to know if somewhere in his `Exception e` there is the information about the variable name - which I think it is not – TripleEEE Dec 07 '16 at 13:34
  • 1
    You can write your own parse method (wrapper around int.Parse) which will provide information about failed value in exception. – Evk Dec 07 '16 at 13:34
  • Even if the exception message would contain this value, there is no guarantee that it contains it tomorrow, or in another language. – Tim Schmelter Dec 07 '16 at 13:35
  • I think the real problem is that you're wrapping multiple calls to `Parse()` in a single `try/catch` block and making the source of the exception ambiguous. – Dan Wilson Dec 07 '16 at 13:35
  • @TripleEEE you are correct, that is my intension – Athafoud Dec 07 '16 at 13:35
  • Best you could do is use the stack trace to figure out which line threw the exception, but then you have to take into account that the line number can change if the code is modified, so what you seem to be looking for is not really something that was built into exceptions in general. – juharr Dec 07 '16 at 13:37

4 Answers4

6

Use TryParse instead (you don't need the overall try catch), example:

int a1=0;
if(!int.TryParse(a, out a1))
{
    //do something here
}
int b1=0;
if(!int.TryParse(b, out b1))
{
    //do something here
}
int c1=0;
if(!int.TryParse(c, out c1))
{
    //do something here
}
fubo
  • 44,811
  • 17
  • 103
  • 137
Andrei Filimon
  • 1,138
  • 8
  • 12
  • This would be my preferred solution. There's no need for exception handling in this situation. – Dan Wilson Dec 07 '16 at 13:38
  • @DanWilson I just thought the same :D Jon is using a sledgehammer to crack a nut. – fubo Dec 07 '16 at 13:39
  • Great answer, but as I said, I know how to do it 'this way'. I am just looking for alternatives and if I can achieve it with `Parse` and `Exceptions` – Athafoud Dec 07 '16 at 13:40
  • 3
    @Athafoud: yes, there are alternatives as evidenced by the other answers, but [exceptions should be for exceptional conditions](http://stackoverflow.com/questions/891217/how-expensive-are-exceptions-in-c). If you're parsing a string then I think it's fair to assume that it may not be an integer. Exception handling is overkill, IMHO. – Dan Wilson Dec 07 '16 at 13:50
5

Not reliably - there's nothing in the FormatException that does this for you. Parsing the message is very fragile - it can change in different versions of .NET, and it'll be localized.

One option would be to write your own Parse method which is interoperable with int.Parse, but throws a subclass of FormatException. For example:

public class ParseException : FormatException
{
    public string OriginalValue { get; }

    public ParseException(string message, string originalValue)
        : base(message)
    {
        OriginalValue = originalValue;
    }
}

public class ExtendedParsing
{
    public int ParseInt32(string value)
    {
        int result;
        if (int.TryParse(value, out result))
        {
            return result;
        }
        throw new ParseException($"Unable to parse \"{value}\"", value);
    }
}

Then you can use it as:

try 
{
    int a1 = ExtendedParsing.ParseInt32(a);
    int b1 = ExtendedParsing.ParseInt32(b);
    int c1 = ExtendedParsing.ParseInt32(c);
}
catch (ParseException e)
{
    Console.WriteLine($"Value that I failed to parse: {e.OriginalValue}");
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
0

What about this simple pattern

string a = "1";
string b = "b";
string c = "3";

int aInt, bInt, cInt;

if (!int.TryParse(a, out aInt))
{
    //report e.g.
    Console.WriteLine($"Could not parse {nameof(a)}");
}

if (!int.TryParse(b, out bInt))
{
    //report e.g.
    Console.WriteLine($"Could not parse {nameof(b)}");
}

if (!int.TryParse(c, out cInt))
{
    //report e.g.
    Console.WriteLine($"Could not parse {nameof(c)}");
}
Hossein Narimani Rad
  • 31,361
  • 18
  • 86
  • 116
  • Great answer, but as I said, I know how to do it 'this way'. I am just looking for alternatives and if I can achieve it with `Parse` and `Exceptions` – Athafoud Dec 07 '16 at 13:40
0

We are using this kind of pattern (mainly to avoid switch/case for localized messages and neutral logger message, not shown here for simplicity, otherwise solution of @JonSkeet with creating custom exception and calling wrapper method is the right way):

string problem = null;
try
{
    problem = "Can't parse a";
    var a1 = int.Parse(a);

    problem = "Can't parse b";
    var b1 = int.Parse(b);

    problem = "Can't parse c";
    var c1 = int.Parse(c);

    problem = "Can't do something";
    ... // something
}
catch(Exception e)
{
    Logger.Add(e);
    UserMessage(problem);
}

The idea is to set reasons prior doing something (optionally clear it after), do it, if it fails - display reason to the user.

Something can be any piece of code, therefore I am not trying to improve parsing specifically by suggesting TryParse.

Sinatr
  • 20,892
  • 15
  • 90
  • 319