aaubry / YamlDotNet

YamlDotNet is a .NET library for YAML
MIT License
2.48k stars 466 forks source link

Aliases do not resolve correctly in Sequences #933

Open MetaFight opened 2 weeks ago

MetaFight commented 2 weeks ago

https://github.com/aaubry/YamlDotNet/blob/23991bd3d22009f7478e9e5c3ac71b106a8da3b7/YamlDotNet/Serialization/NodeDeserializers/ArrayNodeDeserializer.cs#L48C13-L53C1

The ArrayNodeDeserializer leverages CollectionNodeDeserializer.DeserializeHelper to deserialize nodes, however, because it doesn't know the final size of the array being deserialized it uses an ArrayList as a temporary result bucket. Because the IList result it passed into CollectionNodeDeserializer.DeserializeHelper is not the final array, any ValuePromises that get eventually resolved here are not reflected in the final array.

I have been able to get around this by using the attached replacement AnchorSafeArrayNodeDeserializer.cs.

You will need to configure your deserialisation builder as follows to use it:

var namingConvention = YamlDotNet.Serialization.NamingConventions.NullNamingConvention.Instance;

var builder =
    new DeserializerBuilder()
        .WithNamingConvention(namingConvention)
        .WithNodeDeserializer(
            inner => new AnchorSafeArrayNodeDeserializer(namingConvention),
            s => s.InsteadOf<ArrayNodeDeserializer>());

It should be noted that the provided AnchorSafeArrayNodeDeserializer uses the BCL ArrayList rather than the version originally defined inline. As such, this solution will probably need to be adjusted if used in a PR.

I would create a PR myself, but I just don't have the time at the moment. I hope this still helps people.

If it helps, I believe the following yaml should reproduce the original issue:

items:
- &g000_FirstGroup
  name: FirstGroup
- &g001_SecondGroup
  name: SecondGroup
  child: &c000_FirstChild
    name: FirstChild
    groups:
    - *g001_SecondGroup
    - *g000_FirstGroup
    - &g002_ThirdGroup
      name: thirdGroup

When deserialized the obj.items[1].groups array will have a null first entry.

MetaFight commented 2 weeks ago

Some work obligations got postponed so I decided to use the spare time to prepare a PR.