C#

Primary constructors are more than syntactic sugar

Switching from a regular constructor to a primary constructor can change when fields get their values. The difference matters when a base constructor calls a virtual member. Steven Giesel shows the difference by looking at the code the compiler generates.

Published
Reading time
3 min read
agent run #13
agent run #13
Go to original steven-giesel.com

Report this story

Is something wrong with the summary, or do you own this content? Your message comes straight to my inbox.

Type of message

Key points

  • In a primary constructor, the parameter is copied into a hidden field before the base constructor call.
  • In a classic constructor, the field is assigned only after the base constructor returns.
  • If the base constructor calls a virtual member, the classic derived field can still read null.
  • The compiler-generated field is not readonly, so it can be reassigned inside the class.
  • Mixing the parameter in a member and a field initializer creates two copies and triggers CS9124.

A primary constructor looks like a shorter way to write a regular constructor, but it can change the order in which state becomes available. The author compares two derived classes that pass a closure to a base constructor, and shows that a base constructor calling a virtual member sees a null value in the classic version and the real value in the primary version. The reason is in the generated code: the primary constructor copies the parameter into a hidden field before the base constructor runs, while the classic version assigns its field only afterwards.

This ordering detail matters in real libraries, where timers or other callbacks may read virtual members before the derived constructor body finishes. The generated field is not readonly, so reassignment is still possible. If you need a readonly guarantee, a field initializer also runs before the base constructor, but mixing the parameter in members and initializers produces a duplicate copy and the CS9124 warning.

Real-world use

  • Building a library whose base class starts a timer that later reads a virtual property
  • Designing a class hierarchy where derived classes pass parameters into base behavior that runs during construction

Why it matters

Before converting a regular constructor to a primary constructor, check whether the base class calls virtual members during construction, since initialization order can change the observed values.

This summary was generated by the agent from the original post on Steven Giesel. The full text and all rights belong to its author and publisher. Go to original

Related stories

Feedback

Found a bug or have an idea? Your message lands straight in my inbox.

Type of message