Primary constructors in C#
There are lots of thoughts on primary constructors in C#. At first they seem like a nice idea, but there are downsides.
Here are some articles, which seem to start positively but become more negative the more you look at it!
- Refactor your C# code with primary constructors
- Thoughts on Primary Constructors in C#
- Dark side of the primary constructors in C# 12
- Thoughts about primary constructors: 3 pros and 5 cons
- Blocking primary constructor member capture using a Roslyn Analyzer
A quick refresh - this is what they look like:
1
2
3
4
5
6
7
8
public class HomeController(ILogger<HomeController> logger) : Controller
{
public IActionResult Index()
{
logger.Log(LogLevel.Trace, "Index action called");
return View();
}
}
This shows the primary constructor being used to initialize a field. There are a few things to note about this:
- the code could also directly access
logger
as well as_logger
-
logger
isprotected
(ie it can be accessed outside this class) -
logger
is mutable (_logger
is not) - you could just use
logger
and not define_logger
This already indicates some problems:
- there’s more than one way to do it, which could lead to inconsistency
- there are ways to do it wrongly:
- ie use both
logger
and_logger
- this gives a compiler warning, but not everyone pays attention to warnings
- ie use both
- it’s easy to confuse constructor parameters with regular variables
Primary constructors were originally introduced for record
types.
In record
s the constructor parameters are immutable and public
.
Conclusion:
The syntax allows for all kinds of inconsistency and confusion,
so it’s up to you to address that.
Probably the best recommendation is:
- use the primary constructor parameter directly in very simple class
- use the primary constructor parameter to initialize a class field in more complex classes
Or just don’t use primary constructors at all
This post is licensed under
CC BY 4.0
by the author.