Skip to content

Analyse implicit fields generated by primary constructors #2278

@definability

Description

@definability

Is your feature request related to a problem? Please describe.

Mapperly can detect primary constructor parameters to fill them in, but it cannot do the reverse: fetch values from the implicit fields created by the primary constructor:

using Riok.Mapperly.Abstractions;

namespace Mappers;

// Model
public class Entity(float value)
{
    public void F()
    {
        value++;
    }
}

// DTO
public class EntityDto
{
    public float Value { get; set; }
}

[Mapper]
public partial class DtoMapper
{
    // Works nice: Mapperly can parse `EntityDto.Value`
    // and map it onto `value` of the `Entity` primary constructor
    //
    // var target = new global::Mappers.Entity(source.Value);
    private partial Entity MapToEntity(EntityDto source);
    // Warning RMG012 : The member Value on the mapping target type Mappers.EntityDto was not found on the mapping source type Mappers.Entity
    // Warning RMG066 : No members are mapped in the object mapping from Mappers.Entity to Mappers.EntityDto (https://next.mapperly.riok.app/docs/configuration/analyzer-diagnostics/RMG066)
    private partial EntityDto MapToEntityDto(Entity source);
}

Describe the solution you'd like

I would like Mapperly to fetch the values of implicit fields created by primary constructors. Currently (C# 14), an AoT-friendly solution does not seem to exist.

Describe alternatives you've considered

The workaround is to use explicit getters that duplicate the primary constructor parameters.
I consider this a workaround rather than a permanent solution because it requires modifying the model to fit the mapping tool.

To keep it short, I make them all public:

using Riok.Mapperly.Abstractions;

namespace Mappers;

// Model
public class Entity(float value)
{
    public float Value { get; set; } = value;
    public void F()
    {
        value++;
    }
}

// DTO
public class EntityDto
{
    public float Value { get; set; }
}

[Mapper]
public partial class DtoMapper
{
    // Works nice: Mapperly can parse `EntityDto.Value`
    // and map it onto `value` of the `Entity` primary constructor
    //
    // var target = new global::Mappers.Entity(source.Value);
    private partial Entity MapToEntity(EntityDto source);
    // Works nice: Mapperly can parse `Entity.Value`
    // and set `Value` of `EntityDto`
    //
    // var target = new global::Mappers.EntityDto();
    // target.Value = source.Value;
    private partial EntityDto MapToEntityDto(Entity source);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions