Skip to content

ResourceCodeDomSerializer fails to assign distinct number suffixes to resources when serializing collection values #12595

@codereader

Description

@codereader

.NET version

8.0.201 (the affected code is still there in .NET 9)

Did it work in .NET Framework?

Yes

Did it work in any of the earlier releases of .NET Core or .NET 5+?

No response

Issue description

The code in ResourceCodeDomSerializer.SerializationResourceManager.SetValue() (around code lines 714) is failing when assigning sequential number suffixes to resource names:

While I cannot provide an quick-and-easy project to reproduce this, I'd like to suggest reading the code instead:

....
// Now find an unused name
string resourceName = nameBase;

// Only append the number when appendCount is set or if there is already a count.
int count = 0;
if (appendCount || _nameTable.TryGetValue(nameBase, out count))
{
    count++;
    resourceName = $"{nameBase}{count}";
}

// Now that we have a name, write out the resource.
SetValue(manager, resourceName, value, forceInvariant, shouldSerializeInvariant, ensureInvariant, applyingCachedResources);
_nameTable[resourceName] = count; // <<--- bug here, _nameTable[nameBase] should be assigned instead
....

The code in .NET 4.8 assigned numbers starting from 1..N (even if only one value was in the _nameTable, so from the comment in the code I assume it has been changed to avoid assigning a number to the very first occurrence.

The bug occurs when generating number suffixes for the same nameBase value more than twice - it will end up using the same number 1 over and over. You'll end up with a _nameTable looking like this:

  • "name" => 0
  • "name1" => 1

"name1" will be overwritten every time after the second.

Steps to reproduce

The bug is recurring in our software when copy/pasting WinForms controls in design mode. We are maintaining a Window Editor application which allows to copy/paste controls. When serializing the controls, the CodeDomSerializer will end up generating code like this (note the resource names, which are always using the number 1 as suffix.

CustomTextField.CustomProperty.AddRange(new CustomAssembly.Controls.Collections.CollectionItem[] {
			((CustomAssembly.Controls.Collections.CollectionItem)(resources.GetObject("CustomTextField.CustomProperty"))),
			((CustomAssembly.Controls.Collections.CollectionItem)(resources.GetObject("CustomTextField.CustomProperty1"))),
			((CustomAssembly.Controls.Collections.CollectionItem)(resources.GetObject("CustomTextField.CustomProperty1"))),
			((CustomAssembly.Controls.Collections.CollectionItem)(resources.GetObject("CustomTextField.CustomProperty1")))});

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions