-
Notifications
You must be signed in to change notification settings - Fork 983
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor SerializationResourceManager
to use Dictionary
instead of HashTable
#8332
Refactor SerializationResourceManager
to use Dictionary
instead of HashTable
#8332
Conversation
@@ -314,7 +313,7 @@ public IDictionaryEnumerator GetEnumerator() | |||
{ | |||
_isReaderDirty = true; | |||
EnsureResData(); | |||
return _resData.GetEnumerator(); | |||
return ((IDictionary)_resData).GetEnumerator(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This part was required, which might make the whole thing pointless if there is a performance cost for the cast?
Ultimately it would be nice if these were updated to be properly typed, but that is a breaking change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IDictionary
is one of the last implemented interfaces, so performance won't be so great.
https://www.thomasclaudiushuber.com/2020/03/05/c-the-order-of-interfaces-is-important-for-casting-performance/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JeremyKuhne I'd love your input on this. The move to generics might be a performance regression here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Casting is not going to measure in a scenario like this. While there is a difference, it is incredibly small. A few nanoseconds are not going to matter in something that won't run more than a few times.
} | ||
|
||
return null; | ||
Dictionary<string, object> ht = GetResourceSet(culture); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nullable declaration?
if (t is not null) | ||
{ | ||
// This is for backwards compatibility and also for the case when our reader/writer don't support metadata. We must merge the original enumeration data in here or else existing design time properties won't show up. That would be really bad for things like Localizable. | ||
Hashtable it = GetResourceSet(CultureInfo.InvariantCulture); | ||
Dictionary<string, object> it = GetResourceSet(CultureInfo.InvariantCulture); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nullable?
...omponentModel/Design/Serialization/ResourceCodeDomSerializer.SerializationResourceManager.cs
Outdated
Show resolved
Hide resolved
...omponentModel/Design/Serialization/ResourceCodeDomSerializer.SerializationResourceManager.cs
Outdated
Show resolved
Hide resolved
@elachlan, I see partial nullability in these files. There are multiple instances that needs to be declared as nullable. |
@dreddy-work Edit: I've created an issue for it at #8342 |
@elachlan , seems some left out causing build failures : src\System.Windows.Forms.Design\src\System\ComponentModel\Design\Serialization\ResourceCodeDomSerializer.SerializationResourceManager.cs(458,40): error CS8632: (NETCORE_ENGINEERING_TELEMETRY=Build) The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. |
@@ -874,23 +803,23 @@ public string SetValue(IDesignerSerializationManager manager, ExpressionContext | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dreddy-work The for loop here has a super weird definition. There are two of these types of for loops within this code file. What would you suggest to do here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Loop is trying to find unique name that wasn't used yet. We could simplify it to do-while for readability and should be able to remove warning. I do not see any other technical advantages though. Let's convert to do-while?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I can write this into a Dictionary<string, int>
and use the baseName as the key. Therefore keeping track of the count. I'll push through once I work out the proper logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dreddy-work done! Both should be easier to understand now I think.
...omponentModel/Design/Serialization/ResourceCodeDomSerializer.SerializationResourceManager.cs
Outdated
Show resolved
Hide resolved
...omponentModel/Design/Serialization/ResourceCodeDomSerializer.SerializationResourceManager.cs
Show resolved
Hide resolved
...omponentModel/Design/Serialization/ResourceCodeDomSerializer.SerializationResourceManager.cs
Outdated
Show resolved
Hide resolved
{ | ||
return CompareValue.Different; | ||
return !parentValue.Equals(value) || parentValue is null ? CompareValue.Different : CompareValue.Same; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if both parentValue
and value
is null?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@elachlan , did you run any tests here? This is core for resource serialization and like to do some unit testing performed with this change and record results before we merge it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not do any manual testing, but did run the Design Unit Tests.
The ordering seemed important here. Because previously it was checking if both were equal before checking for null. Meaning that its designed to allow both to be null for Same
to be returned. So I replicated that logic here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you try a simple application with multiple sets of controls and localize the application?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no idea how to do this. You mean as a part of one of the test projects?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, by replacing binaries locally on your machine and create .NET 8.0 targeted application. Here are instructions on private testing in case you have not used them before: https://github.com/dotnet/winforms/blob/main/docs/testing.md
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was playing around with the tests, the code is only hit in SerializationResourceManager
when the PrimitiveCodeDomSerializer
is serializing a string with a char count > 200. This isn't tested for.
I tried testing this scenario and writing a separate test class for ResourceCodeDomSerializer
. Both resulted in exceptions due to either a missing session. If I manually created a session, then the exception would be on SerializationResourceManager.Writer
with a missing ResourceWriter
service.
If I could work out how to add a writer service in the test, then I can write tests for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good to know that. Logically, change is no-op here. Lets take it in after addressing rest of the comments.
ResourceCodeDomSerializer.SerializationResourceManager
to replace usages ofHashtable
.ResXResourceReader
to useDictionary
instead ofListDictionary
Related: #8143
Microsoft Reviewers: Open in CodeFlow