簡體   English   中英

為什么過濾此 IEnumerable 會引發 NullReferenceException?

[英]Why filtering this IEnumerable throws an NullReferenceException?

我有一個似乎無法解決的特殊問題。 我很確定這個錯誤來自我對 LINQ 查詢的工作原理缺乏深入了解

  • 以下服務返回產品列表並且工作正常(沒有什么是空的)

    IEnumerable<Product> products = await _productRepository.GetProductList();

    我已經測試了退回的產品,它們的屬性(例如,名稱、價格、描述)都不是 null。 事實上,我可以將它們展示在桌子上。

  • 但是,如果我嘗試過濾返回的產品,我會收到NullReferenceException

IEnumerable<Product> products =products.Where(x=>x.Name.ToLower().StartsWith(keyword.ToLower())).ToList();

即使我檢查了屬性Name is not null,上面的代碼也會拋出NullReferenceException (實際上,沒有什么是 null)

如何解決這個問題?

此代碼無法編譯:

IEnumerable<Product> products = await _productRepository.GetProductList();
IEnumerable<Product> products = products.Where(x=>x.Name.ToLower().StartsWith(keyword.ToLower())).ToList();

所以你需要做一些與你的例子有所不同的事情:

如果你有類似的東西:

IEnumerable<Product> products = await _productRepository.GetProductList()
    .Where(x=>x.Name.ToLower().StartsWith(keyword.ToLower()))
    .ToListAsync();

...那么這應該編譯。 此語句中的NullReferenceException可能來自keyword null。

正如上面的評論中提到的,這是一種非常糟糕的取回數據的方式。 問題是,如果您的存儲庫返回IEnumerable ,它會將所有產品加載到 memory 中,只會讓您的消費代碼過濾到少數幾個。

如果您正在使用單元測試,我建議的存儲庫模式是讓存儲庫返回IQueryable<TEntity>而不是IEnumerable<TEntity>以便您的消費代碼可以應用過濾等內容:

消費語句將是相同的:

IEnumerable<Product> products = await _productRepository.GetProductList()
    .Where(x=>x.Name.ToLower().StartsWith(keyword.ToLower()))
    .ToListAsync();

...除了這種方式, Where條件將應用於 EF 生成的 SQL,從而實現更高效的查詢。 這需要確保 DbContext 實例的范圍涵蓋調用者和存儲庫。 (例如,通過依賴注入提供並限定在 web 請求的生命周期內)

如果您不使用單元測試,那么存儲庫模式不會添加任何內容,直接使用 DbContext 來生成高效查詢會更有效。

不確定您要如何解決 null 的情況,但我猜您的情況可以假設它不是以關鍵字開頭的。 Null 條件運算符與 null 結合是您最好的選擇。 老實說,您應該始終預期 null 參考並知道您想如何處理它們。 我假設關鍵字是一個常數,但如果不是,也應該檢查 null

products = products
    .Where(x => x?.Name?.ToLower().StartsWith(keyword.ToLower()) ?? false)
    .ToList();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM