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.
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~
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.
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:
Don’t:
1 | public class ServiceClass |
Prefer:
1 | public class ServiceClass |
Variables initialized once but not const should be readonly
.
Don’t:
1 | string a = "Hello"; |
Prefer:
1 | string a = "Hello"; |
Or:
1 | StringBuilder builder = new StringBuilder(); |
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.
Don’t:
1 | [ ] |
Prefer:
1 | [ ] |
C# 11.0 allows the usage of generic Attribute
instead of using the typeof
operator.
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.
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!