2023-10-16 17:04:12 +02:00

80 lines
4.1 KiB
Plaintext

== Why is this an issue?
In the interests of readability, code that can be simplified should be simplified. To that end, there are several ways https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerable-1[IEnumerable] language integrated queries (LINQ) can be simplified.
This not only improves readabilty but can also lead to improved performance.
== How to fix it
Simplify the LINQ expressions:
* Use https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.oftype[OfType] instead of https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.select[Select] with the https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#as-operator[as operator] to type cast elements and then null-checking in a query expression to choose elements based on type.
* Use `OfType` instead of using https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.where[Where] and the https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#is-operator[is operator], followed by a cast in a `Select`
* Use an expression in `Any` instead of `Where(element => [expression]).Any()`.
* Use the https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.count[Count] or https://learn.microsoft.com/en-us/dotnet/api/system.array.length[Length] properties instead of the https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.count[Count() method] when it's available (unless you use the predicate parameter of the method for filtering).
* Don't call https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.toarray[ToArray()] or https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.tolist[ToList()] in the middle of a query chain.
Using https://learn.microsoft.com/en-us/ef/[Entity Framework] may require enforcing client evaluations. Such queries should use https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.asenumerable[AsEnumerable()] instead of `ToArray()` or `ToList()` in the middle of a query chain.
=== Code examples
==== Noncompliant code example
[source,csharp,diff-id=1,diff-type=noncompliant]
----
public void Foo(IEnumerable<Vehicle> seq, List<int> list)
{
var result1 = seq.Select(x => x as Car).Any(x => x != null); // Noncompliant; use OfType
var result2 = seq.Select(x => x as Car).Any(x => x != null && x.HasOwner); // Noncompliant; use OfType before calling Any
var result3 = seq.Where(x => x is Car).Select(x => x as Car); // Noncompliant; use OfType
var result4 = seq.Where(x => x is Car).Select(x => (Car)x); // Noncompliant; use OfType
var result5 = seq.Where(x => x.HasOwner).Any(); // Noncompliant; use Any([predicate])
var num = list.Count(); // Noncompliant; use the Count property
var arr = seq.ToList().ToArray(); // Noncompliant; ToList is not needed
var count = seq.ToList().Count(x => x.HasOwner); // Noncompliant; ToList is not needed
}
----
==== Compliant solution
[source,csharp,diff-id=1,diff-type=compliant]
----
public void Foo(IEnumerable<Vehicle> seq, List<int> list)
{
var result1 = seq.OfType<Car>().Any();
var result2 = seq.OfType<Car>().Any(x => x.HasOwner);
var result3 = seq.OfType<Car>();
var result4 = seq.OfType<Car>();
var result5 = seq.Any(x => x.HasOwner);
var num = list.Count;
var arr = seq.ToArray();
var count = seq.Count(x => x.HasOwner);
}
----
== Resources
=== Documentation
* https://learn.microsoft.com/en-us/dotnet/csharp/linq[Language Integrated Queries in C#]
ifdef::env-github,rspecator-view[]
'''
== Implementation Specification
(visible only on this page)
=== Message
* Use "OfType<T>()" here instead.
* Drop "Where" and move the condition into the "Any".
* Drop "ToArray" from the middle of the call chain.
* Replace "ToArray" with "AsEnumerable" in the middle of the call chain.
'''
== Comments And Links
(visible only on this page)
endif::env-github,rspecator-view[]