2013-05-01 18 views
6

我喜歡LINQ語句以表達語法和其他方便的功能。不過,我覺得有時候調試起來很麻煩。具體來說,當我在集合上運行LINQ語句並且集合中的某個元素導致異常時,如何才能找出問題的輸入以及問題的來源?以每個元素爲基礎調試LINQ

想象我有1000張實數的文本文件:

0.46578 
12.314213 
1.444876 
... 

我讀這是一個List<string>並將其加載到一個更具體的數據結構:現在

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

,此特別的輸入,我沒有仔細看看它,結果顯示第876行包含(行號顯示):

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

無論出於何種原因(可能文件是由發生故障的腳本生成的)。我的LINQ方法鏈當然會拋出異常。問題是,我如何確定列表中的哪個元素導致異常,以及它的價值是什麼?

爲了澄清,如果不是我用一個for循環:

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

那麼例外將突出這就要求double.Parse的字符串,我將能夠鼠標移到row很容易地看到哪些問題輸入是。

我當然可以使用Resharper將我的LINQ語句轉換爲for-loops,然後調試它們,但有沒有更好的方法?

+0

什麼樣的LINQ的這是什麼? EF或LINQ to SQL? – 2013-05-01 19:47:10

回答

3

將條件斷點放在條件爲s.StartsWith(「5.56」)的lambda函數上。你只需要把你的光標放在lambda上並按下F9。假設你正在使用visual studio。

2
var data = file_contents.Select(s => { 
    try 
    { 
     return double.Parse(s); 

    } 
    catch 
    { 
     throw; //breakpoint? 
    } 
}); 
0

我只是個人使用tryparse。

 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是一個簡單的擴展方法我寫了我的概念測試程序的一點證明

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

編輯

的WriteDataToTextbox是出來寫一個IEnumerble<T>泛型方法文本框。

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

忘了把輸出放在這裏,所以我想我應該這樣做。它顯示了導致問題的不良數據和數據本身的索引。

Good Data: 
0.46578 
12.314213 
1.444876 


Bad Data: 
[2, Error: Could not calculate value.] 
+0

非常感謝您評論的建設性。既然你有更好的方法,你會發布自己的答案,這不是「你見過的最糟糕的LINQ用法」。 – Charles380 2013-05-01 19:21:19

+0

這裏主要的問題是,你的解決方案迭代數據''2 + I'次,其中'I'是不正確的行數 - 'IndexOf'從每次調用時開始迭代集合。你也可以每行解析至少兩次,其中大部分是三次(兩個'TryParse'和一個'Parse'以獲得更好的值)。這不是很有效,是嗎?我發佈了我的答案,隨時批評它! – MarcinJuraszek 2013-05-01 19:42:58

+0

讓我來告訴你如何直接從你的評論中獲得代碼,使代碼更加高效,從而避免非構造性部分。 「你的解決方案迭代了數據2 + I次,其中我是不正確的行數 - IndexOf每次調用時都會從頭開始迭代該集合,並且每行至少解析兩次,其中大部分解析三次(兩個TryParse和一個解析爲好值)。已經有選擇過載索引提供..使用.Select((s,i)=>我是indexOf「 – Charles380 2013-05-01 20:57:35

0

我不確定你爲什麼不喜歡foreach這裏循環。無論如何,LINQ都會使用它,正如你已經意識到使用LINQ有一些優缺點,並且調試是缺點之一。

我可能會用foreach混合LINQ和具有下列結束:

// 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})) 
{ 
    // x.s - line string 
    // x.i - line number 

    double value; 
    if (double.TryParse(x.s, out value)) 
     data.Add(value);  // add value, which was OK 
    else 
     incorrectRows.Add(x.i); // add index of incorrect value 
} 

這將阻止所有的異常,並給你行號爲所有不正確的值。它也遍歷file_contents只有一次,每個值只被解析一次。

1

聲明:我OzCode工作

LINQ調試很難交界不可能使用Visual Studio。我建議你嘗試使用OzCode。

這就是您的代碼在調試時的樣子(第6項中的例外)。 Debugging LINQ exception

你可以知道哪些項目通過調查認爲那裏傳遞到選擇子句中的項目引起異常 - 和自上次觸發一個例外 - 它很容易找到有問題的值。

如果你有興趣,你可以嘗試OzCode的LINQ調試 - 我們剛剛啓動了一個EAP