Enable nullability in ResourceCodeDomSerializer.SerializationResourceManager#9457
Conversation
| // Provide null as a sentinel so we don't repeatedly ask for the same resource. If this is the invariant culture, always provide one. | ||
| ResourceTable[culture] = culture.Equals(CultureInfo.InvariantCulture) | ||
| ? new Dictionary<string, object>() : s_resourceSetSentinel; | ||
| ? new Dictionary<string, object?>() : null; |
There was a problem hiding this comment.
Before #8332 the sentinel value used to be an object. As ResourceTable was a Hashtable, it was fine putting both dictionaries and simple objects in it. But changing it to a strongly typed dictionary, the type of the sentinel was also changed to a dictionary. The problem with that approach is that now we're actually updating the sentinel dictionary. Replacing the sentinel object by null should solve it
...omponentModel/Design/Serialization/ResourceCodeDomSerializer.SerializationResourceManager.cs
Show resolved
Hide resolved
8da1243 to
313e277
Compare
|
Thank you for taking this on. |
0af7d7f to
1b25b11
Compare
|
Note that if we merge this in .Net 9 timeframe, we are going to keep a bug that was not here in .Net 7. Is this deemed less risky than taking a fix so late? @dreddy-work |
1b25b11 to
094c46c
Compare
|
@dreddy-work do you want me to send over a PR just with the bugfix for .Net 8? |
Yes please. We are trying to mitigate risk by limiting what we ship in .NET 8.0. |
I'd just submit the PR and let them decide. |
094c46c to
b2d88cc
Compare
|
Now that #9642 was merged, I rebased this one, removing the second commit that was about the bugfix. |
b2d88cc to
fbed8c8
Compare
fbed8c8 to
f8d7c8f
Compare
f8d7c8f to
c5daded
Compare
lonitra
left a comment
There was a problem hiding this comment.
I added a few comments. Appreciate your patience here
...omponentModel/Design/Serialization/ResourceCodeDomSerializer.SerializationResourceManager.cs
Outdated
Show resolved
Hide resolved
| manager.GetContext<PropertyDescriptor>()!, | ||
| manager.GetContext<ExpressionContext>()!); |
There was a problem hiding this comment.
Please add comment of how do we know these are not null
There was a problem hiding this comment.
Well, I don't know the actual reason... I just know the call sites of those properties always expect them not to be null as they are used as parameters in manager.Context.Push calls. That's another case of inconsistent checks I think
There was a problem hiding this comment.
I see, it looks like these are used as arguments to manager.Context.Push only when isMetadata = false. So it seems that it is OK for ResourceEntry.PropertyDescription and ResourceEntry.ExpressionContext to be nullable and should be annotated as so. If these are null when isMetadata = false, we should actually throw ArgumentException here since manager did not have the non-nullables required instead of later getting an ArgumentNullException from manager.Context.Push which might be confusing.
There was a problem hiding this comment.
I've pushed something to address this. I've tried to stick to what you indicated. Let me know if this needs some more tweaking
...omponentModel/Design/Serialization/ResourceCodeDomSerializer.SerializationResourceManager.cs
Outdated
Show resolved
Hide resolved
|
|
||
| // Note that when we read metadata, for backwards compatibility, we also merge in regular data from the invariant resource. We need to clear that data here, since we are going to write out metadata separately. | ||
| invariant.Remove(resourceName); | ||
| invariant!.Remove(resourceName); |
There was a problem hiding this comment.
How do we know this is not nullable?
There was a problem hiding this comment.
GetResourceSet returns null only in an error scenario. Which I know is not satisfying... As often in internal classes, checks are pretty inconsistent
There was a problem hiding this comment.
Generally we are moving to add comments whenever ! is used, but given that the codebase is so old, it can be hard to determine when exactly things are null in which case we should throw a specific exception instead of getting an NRE. For this case I think the right answer would be to throw an InvalidOperationException, but of course if there was more context, we should throw exception that would be most helpful.
if (invariant is null) {
throw new InvalidOperationException();
}
invariant.Remove(resourceName);There was a problem hiding this comment.
I was too quick in my first reply. Turns out that we can perfectly explain why invariant can't be null. I've added a comment near the null forgiving operator (which move earlier in the code).
...System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/ComponentCache.cs
Outdated
Show resolved
Hide resolved
d537771 to
5d38185
Compare
As dicussed here
Proposed changes
SerializationResourceManagerto useDictionaryinstead ofHashTable#8332Microsoft Reviewers: Open in CodeFlow