Skip to content

Add support for nullable reference types - Serialization#7859

Open
soujay wants to merge 3 commits into
masterfrom
nullable-serialization
Open

Add support for nullable reference types - Serialization#7859
soujay wants to merge 3 commits into
masterfrom
nullable-serialization

Conversation

@soujay

@soujay soujay commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

This PR enables #nullable enable on the files in the folder, and removes the following from NullableAnnotations.ApproveNullableTypes.approved.txt

  • NServiceBus.Serialization.IMessageSerializer
  • NServiceBus.Serialization.SerializationDefinition
  • NServiceBus.Serialization.SerializationExtensions`1
  • NServiceBus.SerializationConfigExtensions
  • NServiceBus.SerializationContextExtensions
  • NServiceBus.SerializationExtensionsExtensions

@soujay
soujay marked this pull request as draft July 14, 2026 18:14
@soujay
soujay marked this pull request as ready for review July 14, 2026 18:25
});
}

static IMessageSerializer CreateMessageSerializer(Tuple<SerializationDefinition, SettingsHolder> definitionAndSettings, IMessageMapper mapper, IReadOnlySettings mainSettings)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure mapper or mainSettings cannot be null?

@soujay soujay Jul 19, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrt to mapper, it cannot be null:
As per line 20
var mapper = context.Settings.Get<IMessageMapper>();

Get() (SettingsHolder.cs:68-71) delegates to Get(string key) (SettingsHolder.cs:78-92), which throws KeyNotFoundException if the key is missing .
So this call either returns a real IMessageMapper or the method never reaches the assignment.
Also the key is always registered before this runs: EndpointConfiguration's constructor and calls Settings.SetDefault(...) for every endpoint, before any Feature.Setup executes. So SerializationFeature always finds it already registered.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrt to mainSettings,
context.Settings, is sourced from FeatureConfigurationContext.Settings, with { get; } only property set once in that class's internal constructor. Being internal means it can only be constructed by our own code, not by user code
But there is one internal place that does create it, and it never passes null. It feeds it a settings object that's already being used successfully on several lines just above it. If that settings object were null, the program would've already crashed before even reaching that point.
So mainSettings can't be null either.

/// </param>
/// <returns>Deserialized messages.</returns>
object[] Deserialize(ReadOnlyMemory<byte> body, IList<Type> messageTypes = null);
object[] Deserialize(ReadOnlyMemory<byte> body, IList<Type>? messageTypes = null);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The messageTypes is already defaulted to null, so the ? is just making the annotation honest about behavior that already existed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants