Min()
/Max()
on SortedSet<T>
CS-P1025The methods Min()
and Max()
come from the Enumerable
interface defined in System.Linq
.
While they may be appropriate for other structures and scenarios, they are not performant for SortedSet<T>
.
Consider using Sorted<T>
's own properties Min
and Max
as they're efficient and tailored for this very purpose.
ToCharArray()
when iterating a string CS-P1004The ToCharArray()
returns a char
array whose elements are the individual characters of the string
on which this method is called. However, this call is particularly redundant within a foreach
statement as foreach
allows you to iterate through the types that implement IEnumerable
or IEnumerable<T>
, such as string
in this case. Therefore, it is recommended that you get rid of this redundant call.
StringBuilder
CS-P1020Instantiating a new instance of StringBuilder
requires the initialization of the underneath buffer that holds the string
contents. Creating a new instance in a loop may have an adverse performance impact. Instead, it is recommended that you initialize StringBuilder
outside the loop and reuse it within the loop by clearing it when required.
record
objects that rely on const
parameters CS-P1022Records are structures that are extensively used in serialization and deserialization. However, if your instance of record
takes in parameters that are class' const
fields, consider reusing the same record
instance instead of instantiating a new one.
Clear()
to set the items in a Span<T>
to their default values CS-P1023The Fill()
method fills Span<T>
with the value specified. However, consider using the Clear()
method instead if you wish to set the items to the default values as it is more performant and designed for this exact purpose.
The .NET runtime ships with a GC (Garbage Collector) that is responsible for allocation and freeing up of memory as deemed necessary during an application's lifetime. It is responsible for automatically handling memory management-related tasks and preventing accidents such as memory leaks, accidental double frees, etc. Manually invoking the GC does not necessarily improve your application's performance and, in some cases, may even adversely impact the performance. If you wish to improve your application's performance, consider measures such as:
Methods such as string.Contains
and string.IndexOf
allow you to search for an occurrence of either a single char or a substring within a string
. If you'd like to search for an occurrence of a single char, it is recommended that you use the appropriate method that takes a char
as a parameter rather than a string
as the former approach is more performant and recommended.
ContainsKey()
to check if a key exists in a Dictionary<T, K>
CS-P1016If you wish to check if a key exists in a Dictionary
, consider using the ContainsKey()
that ideally has a complexity of O(1). Using the .Keys.Contains()
deteriorates the performance as it has a complexity of O(n) where n = number of elements in your Dictionary
.
Environment.ProcessId
to fetch process ID instead of Process.GetCurrentProcess().Id
CS-P1012You can use GetCurrentProcess().Id
to access the running program's process ID. However, this is an expensive call as it first allocates a Process
instance which then needs to be disposed, all just to get the running program's process ID. An efficient alternative is to just use the static
field Environment.ProcessId
.
Environment.ProcessPath
to fetch process path instead of Process.GetCurrentProcess().MainModule.FileName
CS-P1013You can use Process.GetCurrentProcess().MainModule.FileName
to access the running program's path. However, this is an expensive call as it first allocates a Process
instance which then needs to be disposed, all just to get the running program's path. An efficient alternative is to just use the static
field Environment.ProcessPath
.
Properties are different than fields and are expensive in terms of performance in some scenarios. It is always recommended that properties not clone and return collections. If you absolutely have to do so, consider turning them into methods.
Environment.CurrentManagedThreadId
to fetch the thread ID instead of Thread.CurrentThread.ManagedThreadId
CS-P1014You can use Thread.CurrentThread.ManagedThreadId
to access the running program's path. However, an easier alternative is to just use the static
field Environment.CurrentManagedThreadId
that does just the same. It is simpler and easier to read and remember.
enum
CS-P1021An enum
by default uses int
as an underlying data type. However, changing this to a type whose size is less than that of int
's is likely an unnecessary optimization as such an optimization would not necessarily yield any performance improvements. Any performance improvements, if gained, however, are likely to be minute.
First()
/Last()
on LinkedList<T>
CS-P1024The methods First()
and Last()
come from the Enumerable
interface defined in System.Linq
.
While they may be appropriate for other structures and scenarios, they are not performant for LinkedList<T>
.
Consider using LinkedList<T>
's own properties First
and Last
as they're efficient and tailored for this very purpose.
.Substring
method CS-P1007Index lookup methods such as IndexOf
, LastIndexOf
, IndexOfAny
, and LastIndexOfAny
return the index of the char
depending on the arguments supplied. Chaining such calls to .Substring
requires that a part of the string be selected and then the char be looked up. Instead, consider calling the index lookup methods directly and then subtracting the begin offset.
Finalizers, i.e., destructors, perform clean-up operations as an instance is picked up for garbage collection (GC). If a class has a finalizer defined, it is added to the Finalize
queue, which is later processed by the GC when deemed appropriate. An empty finalizer adds unnecessary additional overhead to the GC since it does not perform effective clean-up operations. Therefore, it is suggested that you either remove the empty finalizer or add relevant clean-up operations.
Environment.ProcessId
instead of Process.GetCurrentProcess().Id
CS-P1002Using Process.GetCurrentProcess().Id
requires that an instance of Process
be allocated to access the required Id
. It then adds additional overhead, i.e., disposing of the Process
instance. It is therefore suggested that you use the reliable and performant alternative Environment.ProcessId
.
static readonly
fields const
CS-P1003Expressions marked as static readonly
do not require an object/instance of a class and can be accessed directly.
Since they're marked as static, they cannot be modified outside a static
constructor. If such fields exist in a class without a static
constructor, it is recommended that you mark them as const
since expressions marked as const
are fully evaluated at the compile-time.
.TryGetValue
to access elements in Dictionary
CS-P1005The .ContainsKey
method allows you to check if a key exists in a Dictionary
while the indexer, i.e. []
allows you to directly access the specified key's value. Using both of them means that you'd be effectively accessing the Dictionary
twice. As an alternative, you can use .TryGetValue
to get a value from a Dictionary
that returns a bool
depending on whether the key exists or not.
.OrderBy()
calls as .ThenBy()
CS-P1008The .OrderBy()
method allows you to specify the criteria according to which the elements must be ordered and returns a new ordering. Everytime the .OrderBy()
method is invoked, the previous ordering, if any, is lost, resulting in a wastage of resources. To preserve any previous ordering, rewrite subsequent .OrderBy()
methods as .ThenBy()
.