Use interfaces and abstract classes
שימוש במחלקות בסיס וממשקים
Don’t:
1 | public class Serializer |
Prefer:
1 | public interface ISerializer |
Instances are created from classes, if your class has no value being an instance - prefer demoting it to an abstract class or an interface.
Prefer using Generic T instead of object
Don’t:
1 | public interface ISerializer |
Prefer:
1 | public interface ISerializer |
This guideline exist to avoid Boxing
.
When a value type is used in the CLR
as object
the virtual machine needs to box
the integer into a heap value which causes memory allocations.
This is one of the differences between Value type
and Reference type
.
Generic values don’t create boxing~
Use record instead of class
Don’t:
1 | public class Person |
Prefer:
1 | public record Person(string Name); |
או:
1 | public record Person |
C# 9.0 added record
classes which make model classes easier to create.
Prefer IEnumerable instead of List or Array
Don’t:
1 | public class Namer |
Prefer:
1 | public class Namer |
When you use a concrete type like List<string>
you make the user to be bound to a specific container type.
You lose couple of advantages to this:
- Multi purpose code.
- The ability to use different containers such as thread-safe containers.
- Make List and Array use immediate memory instead of Lazy algorithms.
- Using Linq with various containers.
Prefer readonly
Don’t:
1 | public class ServiceClass |
Prefer:
1 | public class ServiceClass |
Variables initialized once but not const should be readonly
.
Prefer StringBuilder to appending strings.
Don’t:
1 | string a = "Hello"; |
Prefer:
1 | string a = "Hello"; |
Or:
1 | StringBuilder builder = new StringBuilder(); |
Avoid is or as
Don’t:
1 | object MyObj = fromObject; |
Prefer:
1 | object MyObj = fromObject; |
The new pattern matching switch case makes our code more readable.
Behind the scene it still uses the same mechanism as null checking and casting, however this will make your code more readable.
Another point is - use the strategy pattern instead of type cast-check.
Use Generic Attributes
Don’t:
1 | [ ] |
Prefer:
1 | [ ] |
C# 11.0 allows the usage of generic Attribute
instead of using the typeof
operator.
Use ref struct to avoid Heap allocations
Don’t:
1 | struct Data |
Prefer:
1 | ref struct Data |
It has many limitations but if your code needs high-end optimization for performance you may use the ref struct
to avoid referencing and boxing.
In performance optimization - prefer ValueTask instead of Task
Don’t:
1 | public Task<byte[]> Read(Stream s); |
Prefer:
1 | public ValueTask<byte[]> Read(Stream s); |
Task
is a reference type - each time you return from an async function you reallocate a heap type.
Therefore ValueTask
exist to avoid those allocations.
Moreover - C# may optimize types like ValueTask<bool>
because only 2 values may exist - true or false.
Thanks for reading!