LINQ debugging for each item

I like LINQ instructions for expressive syntax and other convenient functions. However, it is very difficult for me to debug them sometimes. In particular, when I run the LINQ statement in the collection and one of the elements in the collection throws an exception, how can I find out what the problem is and where the problem came from?

Suppose I have a text file with 1000 real numbers:

0.46578 12.314213 1.444876 ... 

I read this as a List<string> and load it into a more specific data structure:

 var file_contents = File.ReadAllLines("myfile.txt"); var data = file_contents.Select(s => double.Parse(s)); 

Now, for this particular input, I did not look at it carefully, and it turns out that the 876th line contains (line numbers shown):

 875 5.56786450 876 Error: Could not calculate value. 878 0.0316213 

For some reason (maybe the file was generated using a script that worked). My LINQ method chain will, of course, throw an exception. The problem is, how can I determine which list item raised an exception, and what is its meaning?

To clarify if I used the for loop instead:

 var data = new List<double>(); foreach(var row in file_contents) { var d = double.Parse(row); data.Add(d); } 

Then the exception will double.Parse line that calls double.Parse , and I could hover over row to easily see what the problem is.

I can of course use Resharper to convert my LINQ statements to for-loops and then debug them, but is there a better way?

+6
source share
5 answers

Place a conditional breakpoint on the lambda function, where the condition is s.StartsWith ("5.56"). You just need to hover over lambda and press F9. Assuming you are using a visual studio.

+3
source
 var data = file_contents.Select(s => { try { return double.Parse(s); } catch { throw; //breakpoint? } }); 
+2
source

Disclaimer: I work for OzCode

LINQ debugging a tight border is not possible using Visual Studio. I suggest you try using OzCode.

This is what your code looks like when debugging (exception in element 6). LINQ exception debugging

You can indicate which element threw an exception by examining the elements that are passed to the Select clause, and since the latter threw an exception, it is easy to find an offensive value.

If you're interested, you can try OzCode LINQ debugging - we just started EAP

+1
source

I would just use tryparse personally.

  var data = new List<string> { "0.46578", "12.314213", "Error: Could not calculate value.", "1.444876", }; double d; var good = data.Where(s => Double.TryParse(s, out d)).Select(Double.Parse); var bad = data.Where(s => !Double.TryParse(s, out d)).Select(x => new { key = data.IndexOf(x), value = x }).ToDictionary(x => x.key, x => x.value); textBox1.AppendTextAddNewLine("Good Data:"); WriteDataToTextBox(good); textBox1.AppendTextAddNewLine(String.Format("{0}{0}Bad Data:", Environment.NewLine)); WriteDataToTextBox(bad); 

AppendTextAddNewLine is just an extension method that I wrote for my little proof of concept testing program

  public static void AppendTextAddNewLine(this TextBox textBox, string textToAppend) { textBox.AppendText(textToAppend + Environment.NewLine); } 

Edit

WriteDataToTextbox is a general method that writes IEnumerble<T> to a text field.

  void WriteDataToTextBox<T>(IEnumerable<T> data ) { foreach (var row in data) { textBox1.AppendTextAddNewLine(row.ToString()); } } 

I forgot to make a conclusion here, so I think I should do it. It shows the index of bad data and the data itself that caused the problem.

 Good Data: 0.46578 12.314213 1.444876 Bad Data: [2, Error: Could not calculate value.] 
0
source

I'm not sure why you don't like the foreach here. LINQ still uses it internally, and as you already understood, there are some pros and cons to using LINQ, and debugging is one of the minuses.

I would probably mix LINQ with foreach and get the following:

 // read all lines from file // var file_contents = File.ReadAllLines("myfile.txt"); // set initial data list length to number of lines for better performance var data = new List<double>(file_contents.Length); // list for incorrect line numbers var incorrectRows = new List<int>(); foreach (var x in file_contents.Select((s, i) => new {s, i})) { // xs - line string // xi - line number double value; if (double.TryParse(xs, out value)) data.Add(value); // add value, which was OK else incorrectRows.Add(xi); // add index of incorrect value } 

This will prevent the exception altogether and give you line numbers for all invalid values. It also file_contents over the file_contents value only once, and each value is parsed only once.

0
source

Source: https://habr.com/ru/post/944039/


All Articles