Skip to content

When binding to interface collections, config generator shouldn't generate logic for both interface & mapping collection type. #89043

Open
@layomia

Description

@layomia

Matching concrete type = actual type to instantiate when binding if needed, e.g.
IList -> List
IDictionary<,> -> Dictionary<,>


Using the Geolocation type from @martincostello's repro for #89010, if an interface such as IList<T> or IDictionary<,> is the target binding type, the generator emits logic for both the interfaces and matching config types e.g.

[Fact]
public void Struct_As_Dictionary_Element()
{
    var configuration = TestHelpers.GetConfigurationFromJsonString("""
        {
            "First":
            {
                "Latitude": 3,
                "Longitude": 4,
            }
        }
        """);

    Geolocation obj = configuration.Get<IDictionary<string, Geolocation>>()["First"];
    Assert.Equal(3, obj.Latitude);
    Assert.Equal(4, obj.Longitude);
}

Generated (buggy output per #89010):

public static void BindCore(IConfiguration configuration, ref IDictionary<string, ConfigurationBinderTests.Geolocation> obj, BinderOptions? binderOptions)
{
    if (obj is null)
    {
        throw new ArgumentNullException(nameof(obj));
    }

    foreach (IConfigurationSection section in configuration.GetChildren())
    {
        if (!(obj.TryGetValue(section.Key, out ConfigurationBinderTests.Geolocation element)))
        {
            element = InitializeConfigurationBinderTestsGeolocation(section, binderOptions);
        }
        var temp439 = InitializeConfigurationBinderTestsGeolocation(section, binderOptions);
        BindCore(section, ref temp439, binderOptions);
        element! = temp439;
        obj[section.Key] = element;
    }
}

public static void BindCore(IConfiguration configuration, ref Dictionary<string, ConfigurationBinderTests.Geolocation> obj, BinderOptions? binderOptions)
{
    if (obj is null)
    {
        throw new ArgumentNullException(nameof(obj));
    }

    foreach (IConfigurationSection section in configuration.GetChildren())
    {
        if (!(obj.TryGetValue(section.Key, out ConfigurationBinderTests.Geolocation element)))
        {
            element = InitializeConfigurationBinderTestsGeolocation(section, binderOptions);
        }
        var temp438 = InitializeConfigurationBinderTestsGeolocation(section, binderOptions);
        BindCore(section, ref temp438, binderOptions);
        element! = temp438;
        obj[section.Key] = element;
    }
}

We only need one of these methods.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-Extensions-ConfigurationenhancementProduct code improvement that does NOT require public API changes/additionssize-reductionIssues impacting final app size primary for size sensitive workloadssource-generatorIndicates an issue with a source generator feature

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions