Share via


CA1851: Mogelijke meerdere inventarisaties van IEnumerable verzameling

Eigenschappen Weergegeven als
Regel-id CA1851
Titel Mogelijke meerdere inventarisaties van IEnumerable verzameling
Categorie Prestaties
Oplossing is brekend of niet-brekend Niet-brekend
Geïntroduceerde versie .NET 7
Standaard ingeschakeld in .NET 9 Nee

Oorzaak

Er zijn meerdere inventarisaties van een IEnumerable verzameling gedetecteerd.

Beschrijving van regel

Een verzameling van het type IEnumerable of IEnumerable< T> heeft de mogelijkheid om opsomming uit te stellen wanneer deze wordt gegenereerd. Veel LINQ-methoden, zoals Selecteren, gebruiken de uitgestelde uitvoering. Opsomming begint wanneer de verzameling wordt doorgegeven aan een LINQ-opsommingsmethode, zoals ElementAt, of wordt gebruikt in een voor elke instructie. Het opsommingsresultaat wordt niet eenmaal berekend en in de cache opgeslagen, zoals Luie.

Als de opsommingsbewerking zelf duur is, bijvoorbeeld een query in een database, kunnen meerdere opsommingen de prestaties van het programma schaden.

Als de opsommingsbewerking bijwerkingen heeft, kunnen meerdere opsommingen leiden tot bugs.

Schendingen oplossen

Als het onderliggende type van uw IEnumerable verzameling een ander type is, zoals List of Array, is het veilig om de verzameling te converteren naar het onderliggende type om de diagnose te herstellen.

Schending:

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

Oplossing:

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

Als het onderliggende type van de IEnumerable verzameling gebruikmaakt van een iterator-gebaseerde implementatie (bijvoorbeeld als deze wordt gegenereerd door LINQ-methoden zoals Select of met behulp van het rendementswoord ), kunt u de schending oplossen door de verzameling te materialiseren. Hiermee wordt echter extra geheugen toegewezen.

Voorbeeld:

Schending:

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

Oplossing:

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

Aangepaste opsommingsmethoden en LINQ-ketenmethoden configureren

Standaard worden alle methoden in de System.Linq naamruimte opgenomen in het analysebereik. U kunt aangepaste methoden toevoegen waarmee een IEnumerable argument in het bereik wordt opgesomd door de enumeration_methods optie in te stellen in een .editorconfig-bestand .

U kunt ook aangepaste LINQ-ketenmethoden (dat wil gezegd: methoden gebruiken een IEnumerable argument en een nieuw IEnumerable exemplaar retourneren) toevoegen aan het analysebereik door de linq_chain_methods optie in te stellen in een .editorconfig-bestand .

De standaardveronderstelling van methoden configureren, nemen IEnumerable parameters

Standaard wordt ervan uitgegaan dat alle aangepaste methoden die een IEnumerable argument accepteren, niet het argument opsommen. U kunt dit wijzigen door de assume_method_enumerates_parameters optie in te stellen in een .editorconfig-bestand .

Wanneer waarschuwingen onderdrukken

Het is veilig om deze waarschuwing te onderdrukken als het onderliggende type van de IEnumerable verzameling een ander type is, zoals List of Arrayals u zeker weet dat methoden die een IEnumerable verzameling nemen, deze niet opsommen.

Een waarschuwing onderdrukken

Als u slechts één schending wilt onderdrukken, voegt u preprocessorrichtlijnen toe aan uw bronbestand om de regel uit te schakelen en vervolgens opnieuw in te schakelen.

#pragma warning disable CA1851
// The code that's violating the rule is on this line.
#pragma warning restore CA1851

Als u de regel voor een bestand, map of project wilt uitschakelen, stelt u de ernst none ervan in op het configuratiebestand.

[*.{cs,vb}]
dotnet_diagnostic.CA1851.severity = none

Zie Codeanalysewaarschuwingen onderdrukken voor meer informatie.

Zie ook