C#

C#

Made by DeepSource
Calling garbage collector manually does not necessarily improve performance CS-P1001
Performance
Critical

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:

Avoid empty finalizers CS-P1000
Performance
Critical
Autofix

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.

Consider using Environment.ProcessId instead of Process.GetCurrentProcess().Id CS-P1002
Performance
Critical

Using 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.

Consider making static readonly fields const CS-P1003
Performance
Major

Expressions 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.

Redundant call to ToCharArray() when iterating a string CS-P1004
Performance
Major
Autofix

The 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.

Consider using the appropriate overloaded method when searching for a single char CS-P1006
Performance
Major
Autofix

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.

Avoid chaining of index lookup and .Substring method CS-P1007
Performance
Major

Index 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.

Consider using .TryGetValue to access elements in Dictionary CS-P1005
Performance
Major

The .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.

Consider rewriting chained .OrderBy() calls as .ThenBy() CS-P1008
Performance
Major

The .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().

Use Array.Empty<T>() to efficiently create empty arrays CS-P1009
Performance
Major
Autofix

Using the new keyword lets you create an array with the length of your choice. However, memory allocation, no matter how big or small, comes at a cost. Instead, it is recommended that you use Array.Empty<T>() to create an empty array as it maintains a readonly static buffer internally, thereby essentially maintaining a single instance instead of multiple copies despite multiple invocations. Refer to the benchmarks mentioned in the references section below for additional info.

Rewrite virtual void Finalize() as ~Destructor() CS-P1010
Performance
Major

Destructors, often represented as ~Foo() (where Foo = class name) are used to perform clean-up operations when being garbage collected. Such calls are translated to override void Finalize() automatically and contain further instructions to invoke the Finalize method recursively for all the instances in the inheritance chain to perform a full clean-up. It is therefore recommended that you let the compiler and runtime do the translation and that you not explicitly define virtual void Finalize(). Additionally, if you wish to perform clean-up operations such as closing file handles and database connections, it is recommended that you take a look at the IDisposable interface as Finalizers are invoked by the runtime when deemed appropriate.

Use the method overload that accepts Span<T> instead of T[] when possible to reduce allocations CS-P1011
Performance
Major

Span<T> is a structure that is allocated on the stack rather than heap, thereby reducing the number of allocations during the program's lifetime which in return exerts less pressure on the GC. Since the method that you're trying to invoke has an overload that accepts Span<T>, it is therefore suggested that you use that overload and pass Span<T> rather than T[].

Consider reusing existing instances of StringBuilder CS-P1020
Performance
Major

Instantiating 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.

Use ContainsKey() to check if a key exists in a Dictionary<T, K> CS-P1016
Performance
Critical
Autofix

If 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.

Use Environment.ProcessId to fetch process ID instead of Process.GetCurrentProcess().Id CS-P1012
Performance
Major
Autofix

You 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.

Use Environment.ProcessPath to fetch process path instead of Process.GetCurrentProcess().MainModule.FileName CS-P1013
Performance
Major
Autofix

You 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.

Use Environment.CurrentManagedThreadId to fetch the thread ID instead of Thread.CurrentThread.ManagedThreadId CS-P1014
Performance
Major
Autofix

You 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.

Passing an identity function to Select() is redundant CS-P1015
Performance
Major

The Select() method from System.Linq transforms an IEnumerable<T>'s elements based on the lambda specified. An identity function is a function that returns the same element unchanged that was passed as its argument. Since such a function does nothing useful, passing it to Select() does not modify the elements and is just a redundant expression. It is recommended that you drop such redundant expressions.

Consider using more appropriate overload StringBuilder.Append(char) CS-P1017
Performance
Critical

The Append() method in StringBuilder has overloads that accept both string and char. If you wish to append a single char, consider calling Append(char) over Append(string) as the former is more performant.

Consider using typeof(T).Assembly to get currently executing assembly CS-P1018
Performance
Critical

As the name suggests, Assembly.GetExecutingAssembly() returns the executing assembly. However, this is not an efficient way. Consider using typeof(T).Assembly instead.