The .NET framework’s XmlSerializer
class allows to control the conditional serialization of individual properties based on a specific (but not well-documented) convention: When deciding whether to serialize a property, the serializer will check if a no-args function with a boolean return value and the name ShouldSerialize{PropertyName}
exists. If it does exist, then the return value of that function determines whether the property will be serialized. If it does not exist, the property will be serialized by default (unless other annotations on the property prevent this).
This is of course pretty fragile. If you decide to refactor your code at a later point and change the name of a property from Foo
to Bar
, you also need to change the name of the function to ShouldSerializeBar
. It’s also easy to get a typo into the function name for more complex property names. In either case will the functionality silently break.
A possible Sonar rule could raise an issue if a class contains a function that
- is public
- is parameterless
- has a boolean return value
- has a name that starts with
ShouldSerialize
(case-sensitive) - does not end with the name of any of the public properties or fields in that class.
While there is of course the possibility of identifying false-positives, it seems a bit unlikely that you would have a function with these very specific requirements without intending to use this pattern.
Non-complian code:
Public Class A
Public Property Foo As Integer
Public Property Bar As New List(Of B)
Public Function ShouldSerializefoo() As Boolean ' NONCOMPLIANT - case mismatch
Return Foo <> 0
End Function
Public Function ShouldSerializeBaz() As Boolean ' NONCOMPLIANT - typo/unknown property
Return Bar IsNot Nothing AndAlso Bar.Count() > 0
End Function
End Class
Compliant code:
Public Class A
Public Property Foo As Integer
Public Property Bar As New List(Of B)
Public Function ShouldSerializeFoo() As Boolean ' COMPLIANT
Return Foo <> 0
End Function
Public Function ShouldSerializeBar() As Boolean ' COMPLIANT
Return Bar IsNot Nothing AndAlso Bar.Count() > 0
End Function
End Class
External references:
This ShouldSerialize{PropertyName}
convention is not only used by the XmlSerializer
, but also with Windows Forms controls (and is probably where it originated before the serializer adopted it):
The convention has also been adapted by other serialization frameworks, such as json.net and protobuf.net:
- https://www.newtonsoft.com/json/help/html/ConditionalProperties.htm
- https://stackoverflow.com/questions/10190167/protobuf-net-conditional-serialization
(I couldn’t find any official documentation regarding the behaviour in the XmlSerializer
. It’s a semi-hidden feature. It’s been around for a while and “just works” this way.)
While there are other naming-convention based functions, like {PropertyName}Specified
and Reset{PropertyName}
, those don’t seem as universally used and more prone to false-positives.
Type:
- Code Smell