Sometimes when working with C# you discover some hidden gems. Some of them very useful, other ones a little bit harder to find a good way to benefit from their functionality. One of those hidden gems that I discovered some days ago is the PrintMembers
method.
Record Types
To explain where you can find this method, I first have to talk about record types. Record types were introduced in C# 9 as a new reference type that you can create instead of classes or structs. C# 10 adds record structs so that you can define records as value types.
Records are distinct from classes in that record types use value-based equality. Two variables of a record type are equal if the record type definitions are identical, and if for every field, the values in both records are equal.
Record types have a compiler-generated ToString method that displays the names and values of public properties and fields:
Person{ FirstName = Bart, LastName = Wullems }
In an application we are building we are using this ToString()
method to generate a cache key. This works great until you add another reference type to your record type:
If we now print out the value, we see the following:
Product { FirstName = Bart, LastName = Wullems, PhoneNumbers = System.String[] }
We no longer have uniqueness what doesn’t make it a good cache key anymore.
PrintMembers
Let’s fix this by implementing a PrintMembers
method on our record type.
Important! If you want to do this, you need to be aware about the following:
- For a
sealed
record that derives fromobject
(doesn't declare a base record):private bool PrintMembers(StringBuilder builder)
; - For a
sealed
record that derives from another record (note that the enclosing type issealed
, so the method is effectivelysealed
):protected override bool PrintMembers(StringBuilder builder)
; - For a record that isn't
sealed
and derives from object:protected virtual bool PrintMembers(StringBuilder builder);
- For a record that isn't
sealed
and derives from another record:protected override bool PrintMembers(StringBuilder builder);
Here is the implementation for our Person
class:
If we now print out the value, all the values are included:
Product { FirstName = Bart, LastName = Wullems, PhoneNumbers = 123/45.67.89,987/65.43.21 }
Nice!
More information: