CA1851:集合的 IEnumerable
可能多個列舉
屬性 | 值 |
---|---|
規則識別碼 | CA1851 |
標題 | 集合的 IEnumerable 可能多個列舉 |
類別 | 效能 |
修正程式是中斷或非中斷 | 不中斷 |
引進的版本 | .NET 7 |
預設在 .NET 8 中啟用 | No |
原因
偵測到集合的 IEnumerable
多個列舉。
檔案描述
IEnumerable 或 IEnumerable< T> 類型的集合能夠在產生列舉時延遲列舉。 許多 LINQ 方法,例如 Select,都會使用延後執行。 列舉會在將集合傳遞至 LINQ 列舉方法時啟動,例如 ElementAt,或用於每個語句的 。 列舉結果不會計算一次並快取,例如 延遲。
例如,如果列舉作業本身的成本很高,對資料庫的查詢,則多個列舉會損害程式的效能。
如果列舉作業有副作用,則多個列舉可能會導致 Bug。
如何修正違規
如果集合 IEnumerable
的基礎類型是某些其他類型,例如 List
或 Array
,則安全地將集合轉換成其基礎類型,以修正診斷。
違規:
public void MyMethod(IEnumerable<int> input)
{
var count = input.Count();
foreach (var i in input) { }
}
Public Sub MyMethod(input As IEnumerable(Of Integer))
Dim count = input.Count()
For Each i In input
Next
End Sub
修正:
public void MyMethod(IEnumerable<int> input)
{
// If the underlying type of 'input' is List<int>
var inputList = (List<int>)input;
var count = inputList.Count();
foreach (var i in inputList) { }
}
Public Sub MyMethod(input As IEnumerable(Of Integer))
' If the underlying type of 'input' is array
Dim inputArray = CType(input, Integer())
Dim count = inputArray.Count()
For Each i In inputArray
Next
End Sub
如果集合的基礎類型 IEnumerable
使用反覆運算器型實作(例如,如果它是由LINQ Select 方法所產生,或是使用 yield 關鍵詞所產生),您可以藉由具體化集合來修正違規。 不過,這會配置額外的記憶體。
例如:
違規:
public void MyMethod()
{
var someStrings = GetStrings().Select(i => string.Concat("Hello"));
// It takes 2 * O(n) to complete 'Count()' and 'Last()' calls, where 'n' is the length of 'someStrings'.
var count = someStrings.Count();
var lastElement = someStrings.Last();
}
Public Sub MyMethod()
Dim someStrings = GetStrings().Select(Function(i) String.Concat(i, "Hello"))
' It takes 2 * O(n) to complete 'Count()' and 'Last()' calls, where 'n' is the length of 'someStrings'.
Dim count = someStrings.Count()
Dim lastElement = someStrings.Last()
End Sub
修正:
public void MyMethod()
{
var someStrings = GetStrings().Select(i => string.Concat("Hello"));
// Materialize it into an array.
// Note: This operation would allocate O(n) memory,
// and it takes O(n) time to finish, where 'n' is the length of 'someStrings'.
var someStringsArray = someStrings.ToArray()
// It takes 2 * O(1) to complete 'Count()' and 'Last()' calls.
var count = someStringsArray.Count();
var lastElement = someStringsArray.Last();
}
Public Sub MyMethod()
Dim someStrings = GetStrings().Select(Function(i) String.Concat(i, "Hello"))
' Materialize it into an array.
' Note: This operation would allocate O(n) memory,
' and it takes O(n) time to finish, where 'n' is the length of 'someStrings'.
Dim someStringsArray = someStrings.ToArray()
' It takes 2 * O(1) to complete 'Count()' and 'Last()' calls.
Dim count = someStrings.Count()
Dim lastElement = someStrings.Last()
End Sub
設定自定義列舉方法和LINQ鏈結方法
根據預設,命名空間中的所有 System.Linq 方法都會包含在分析範圍中。 您可以藉由在 .editorconfig 檔案中設定 enumeration_methods
選項,將列舉IEnumerable
自變數的自定義方法新增至範圍。
您也可以藉由在 .editorconfig 檔案中設定 linq_chain_methods
選項,將自定義的 LINQ 鏈結方法(也就是方法接受IEnumerable
自變數並傳回新的IEnumerable
實例)新增至分析範圍。
設定方法採用 IEnumerable
參數的預設假設
根據預設,會假設接受 IEnumerable
自變數的所有自定義方法都不會列舉自變數。 您可以在 .editorconfig 檔案中設定 assume_method_enumerates_parameters
選項,以變更此專案。
隱藏警告的時機
如果集合的基礎IEnumerable
類型是 或 Array
之類的其他類型List
,或如果您確定採用IEnumerable
集合的方法未列舉,則隱藏這個警告是安全的。
隱藏警告
如果您只想要隱藏單一違規,請將預處理器指示詞新增至原始程式檔以停用,然後重新啟用規則。
#pragma warning disable CA1851
// The code that's violating the rule is on this line.
#pragma warning restore CA1851
若要停用檔案、資料夾或項目的規則,請在組態檔中將其嚴重性設定為 。none
[*.{cs,vb}]
dotnet_diagnostic.CA1851.severity = none
如需詳細資訊,請參閱 如何隱藏程式代碼分析警告。