2013-10-23 53 views
5

我有一些我真的不喜歡的代碼的一部分,如果有可能以某種方式簡化它 - 會非常好。簡化LINQ表達式

A a; // I want to get rid of this variable 
if((a = collection.FirstOrDefault(x => x.Field == null)) != null) 
{ 
    throw new ScriptException("{0}", a.y); //I need to access other field of the object here, that's why I had to declare a variable outside of the expression 
} 
+3

你需要變量,除非你想執行兩次表達式 – Jonesopolis

+0

@Jonesy這就是我所害怕的。 – Anarion

+0

@Aarreion我想你會害怕'TryParse'和'Tryxxx'模式。 –

回答

7

你可以讓你的代碼更具可讀性,如果你將結合變量賦值和定義:

A a = collection.FirstOrDefault(x => x.Field == null); 

if(a != null)  
    throw new ScriptException("{0}", a.y); 
+1

謝謝。易讀易用。並感謝其他人 - 很多好的答案。 – Anarion

+0

@IAbstract抱歉,錯字。固定! –

+0

無法在這個和@Servy之間選擇。你的可讀性好。塞爾比的得到的「開箱」)) – Anarion

7

而不是尋找相匹配的第一個項目,處理的是,把結果作爲一個集合。 foreach對所有匹配使用Where的項目。由於異常將帶你回到了循環的最終結果是相同的,只是更乾淨的代碼:

foreach(var a in collection.Where(x => x.Field == null)) 
    throw new ScriptException("{0}", a.y); 

如果你想更清楚該循環將最多隻執行一次的讀者,你可以在裏面添加一個Take呼叫澄清代碼不作任何功能性的改變:

foreach(var a in collection.Where(x => x.Field == null).Take(1)) 
    throw new ScriptException("{0}", a.y); 

這也使得它更容易聚集所有的無效項目,而不是第一:

var exceptions = collection.Where(a => a.Field == null) 
    .Select(a => new ScriptException("{0}", a.y)) 
    .ToList(); 
if (exceptions.Any()) 
    throw new AggregateException(exceptions); 
+0

一個很好的開箱即用的方法,但我會假設OP計劃稍後使用'a'如果不拋出異常 – musefan

+0

噢,那是......我不知道,我認爲這是誤導性的代碼,因爲那裏將永遠不會是循環的任何迭代。這當然更簡潔,但我會說原始代碼更容易理解。 –

+0

@musefan不,我不想,我想擺脫A. – Anarion

1

在這種情況下,您無法擺脫A a。您需要存儲從LINQ語句返回的值以便稍後使用,並且與using塊不同,if語句不允許您在其表達式中定義變量。

就個人而言,我應該這樣做:

A a = collection.FirstOrDefault(x => x.Field == null); 
if(a != null) 
{ 
    throw new ScriptException("{0}", a.y); 
} 
+0

這不是擺脫局部變量,因爲問題是要求。 – Servy

+0

我知道。我說這是不可避免的。我會像其他人一樣提到,並將聲明和分配結合起來,使代碼更清晰。 –

+0

@Servy其實OP要求簡化代碼 –

2

你無法避免聲明變量,因爲你需要分配if之外,然後引用裏面的值。 (唯一的方法是執行兩次過濾器,這可能會很昂貴)。

這就是說,你可以用你的優勢,使代碼更易讀:

A a = collection.FirstOrDefault(x => x.Field == null); // assign here 
if(a != null) // more easily-readable comparison here 
{ 
    throw new ScriptException("{0}", a.y); 
} 
0

你可以使用一個.Select刪除外參考a,雖然結果是怎麼樣的還是一個爛攤子:

collection.Where(x => x.Field == null) 
    .Select(a => string.Format("{0}", a.y)) 
    .Take(1).ToList().ForEach(msg => 
     throw new ScriptException(msg); 
    ); 

Take(1)如果沒有匹配項目返回一個空的枚舉,使得在ForEach塊將運行零個或一個時間。

+0

這不會過濾出「Field」爲空的項目。 – Servy

+0

您使用的是什麼樣的「選擇」? –

+0

你需要在選擇之前做過濾器*,否則你不能訪問該字段,你的選擇會搞砸,而這只是我之前發佈的較差版本的答案。 – Servy

1

所以你的邏輯是:如果有任何項目沒有字段,拋出異常。

var a = collection.Where(x => x.Field == null); 
if(a.Any()) 
{ 
    throw new ScriptException("{0}", a.First().y); 
} 

一個更好的方法可能是整理他們:

var a = collection.Where(x => x.Field == null).Select(x => x.y); 
if(a.Any()) 
{ 
    throw new ScriptException("{0}", string.Join(',', a)); 
} 

這樣,你可以看到所有的實例。

+1

請注意,這枚舉收集兩次,而不是所有其他答案一次。 – Servy

+0

啊,對,我可以解決這個問題。 – Magus

0

這個工作適合你嗎?這很醜陋,但你可以在lambda中拋出異常。

collection.FirstOrDefault(x => { 
           if(x.Field == null) 
           { 
             throw new ScriptException("{0}", x.y); 
           } 
           return false; 
           } 
         );