โ How to resolve CS9017 when trying passing captured arguments by primary constructor to base class?
I am using C# 12.
The base class:
The derived class:
Everything works well without any warnings. Rider told me the
LocalDbExtension
constructor can be converted into primary constructor, and helped me executed the conversion. Now it looks like this:
Now, when I build the project, compiler tells me:
From the doc:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/constructor-errors#primary-constructor-syntax CS9107 - Parameter is captured into the state of the enclosing type and its value is also passed to the base constructor. The value might be captured by the base class as well. This warning indicates that your code may be allocated two copies of a primary constructor parameter. Because the parameter is passed to the base class, the base class likely uses it. Because the derived class accesses it, it may have a second copy of the same parameter. That extra storage may not be intended.I have no idea how to resolve this warning if keeping using primary constructor on this class.
Resolve errors related to constructor declarations
These compiler errors and warnings indicate violations when declaring constructors in classes or structs, including records. This article provides guidance on resolving those errors.
12 Replies
Show your whole type
I just tried to create a minimal reproducible example.
I deleted all business-related fields, properties and methods.
Now, ignoring Warning CS9113, the warning CS9107 mentioned above happens to
appConfig
.Well, that simple example quite nicely demonstrates the issue ๐
You are passing
appConfig
to the DbExtensionTest
, and also referencing it (ie, capturing it) into LocalDbExtensionTest
If you want appConfig
to be visible in derived types, make a protected field in DbExtensionTest
, and reference the field in LocalDbExtensionTest
Or, don't pass the value to the base typeOh thanks! I will try it.
The point of this issue is to avoid double storage. Imagine that you had this slight modification of that example:
Note how both
DbExtensionTest
and LocalDbExtensionTest
capture appConfig
. The captures aren't mutually visible, so both types need to capture appConfig
, unnecessarily storing the field twice
You honestly probably had this problem initially (since you had a private field in the derived type and passed the value to the base type), but no one was warning you about itThanks, I understand that passing to base class and referencing a parameter will result in double storage. I need to change one of them.
1. Not referencing
appConfig
in derived class:
2. Or not passing appConfig
to base type.
I am not sure if I do not pass appConfig
to base type, how I can access appConfig
in base type.Is this a library someone else may depend on and derive from
DbExtensionTest
?
If you need it in the base type, then you need to pass it, and will need to do one of the things you mentioned in 1No, all codes pasted here are coded by me.
Then I'd just do a field, and let SonarLint know that they have a false positive
Got that. Thanks!
Just tag the related issue here. This report exists.
https://github.com/SonarSource/sonar-dotnet/issues/7624
GitHub
Fix S3604 FP: Primary constructors ยท Issue #7624 ยท SonarSource/sona...
Description S3604 is reported for classes with primary constructors. Repro steps class SampleClass(object options) { private readonly object _options = options; // Noncompliant - FP: S3604 shouldn&...
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.