2017-05-04 99 views
0

我有以下擴展功能:如何使用yield返回空集合?

public static IEnumerable<T> Select<T>(this IDataReader reader, 
           Func<IDataReader, T> selector) 
{ 
    while (reader.Read()) 
    { 
     yield return selector(reader); 
    } 
} 

正在使用,如:

var readFields = dsReader.Select(r => 
{ 
    var serviceResponse = myService.Decrypt<DateTime>(r.GetString(DATE_VALUE), r.GetInt32(DEK_ID)); 

    if (serviceResponse.IsSuccessful) 
    { 
     return new DataField<DateFieldValue> 
     { 
      FieldValue = new DateFieldValue { Data = serviceResponse.Value } 
     }; 
    } 
    return null; 
}); 

if (!readFields.IsCollectionNullOrEmpty()) 
         returnFinalFields.AddRange(readFields); 

我這裏面臨的是,即使是serviceResponse.IsSuccessful假閱讀字段不爲空,它包含的問題具有null的項目的枚舉。有沒有辦法可以在這裏返回一個空集合?

+3

'Enumerable.Empty ();' –

+0

有沒有一種方法)的reader.Read前檢查(見如果有數據,並在進入之前返回null? – Neil

+2

@Neil從預期的'IEnumerable '返回null幾乎總是反模式。 –

回答

0

有趣的(誤?)使用的Select。當IsSuccessfulfalse時,您的問題是您從Select代表返回null。由於沒有返回從Select的代表值是不是一種選擇,過濾器算賬:

var readFields = dsReader.Select(r => { 
    var serviceResponse = myService.Decrypt<DateTime>(r.GetString(DATE_VALUE), r.GetInt32(DEK_ID)); 

    if (serviceResponse.IsSuccessful) 
     return new DataField<DateFieldValue> { 
      FieldValue = new DateFieldValue { Data = serviceResponse.Value } 
     }; 
    else 
     return null; 
}).Where(df => df != null); 
1

Select方法可以檢查返回的結果,並且只有在有效時才產生它的值。例如不null

public static IEnumerable<T> Select<T>(this IDataReader reader, Func<IDataReader, T> selector) 
    where T:class 
{ 
    while (reader.Read()) 
    { 
     var res = selector(reader); 
     if(res!=null) 
      yield return res; 
    } 
} 

雖然Servy如所說的那樣,通常不會在常規Select屬於。該方法可以稱爲SelectValidValues,以避免混淆。

另一種方法是讓lambda參數返回一個包含結果和是否有效的Tuple。 另一種方法是有一個可選參數(作爲一個值或一個額外的謂詞函數)來檢查哪些值是有效的

+1

然後它不再選擇。這不屬於「選擇」方法。 – Servy

+1

@Servy確實,但也許OP有不同的想法如何'選擇'應該表現?重命名爲'SelectNotEmpty'對於公共代碼來說可以。 –

+0

@AlexeiLevenkov這只是創建一個新問題。 LINQ沒有'SelectNotEmpty'方法是有原因的。如果要投影,則使用投影方法,如果要過濾,則使用濾鏡方法。你不要將它們組合成一個可以做兩件不相關事情的單一方法。此外,在這裏依然使用'null'作爲表示失敗響應的語義錯誤。 *那*是需要解決的問題。 – Servy

2

這裏真正的問題是,你不想選擇一個null值,當服務沒有成功的迴應。你會想篩選出成功的響應作爲查詢的一部分:

var readFields = from r in dsReader 
    let serviceResponse = myService.Decrypt<DateTime>(r.GetString(DATE_VALUE), r.GetInt32(DEK_ID)) 
    where serviceResponse.IsSuccessful 
    select new DataField<DateFieldValue> 
    { 
     FieldValue = new DateFieldValue { Data = serviceResponse.Value } 
    }; 
+0

或者在lambda語法中'var readFields = dsReader.Select(r => myService.Decrypt其中(sr => sr.IsSuccessful).Select(new DataField {FieldValue = new DateFieldValue {Data = serviceResponse.Value}}); ' – NetMage

+0

順便說一句,非常好的問題反轉,使其更優雅。 – NetMage