Skip to content

[Improvement] - Add by default using optimum constructor selector to unify the choice of constructor for types #892

Description

@DocSvartz

Since the restriction of having a default constructor new() for classes is no longer mandatory,
and the constructor can using default values ​​for the parameter type.

Optimality criterion(MappingScore) = maximum count of not mapped params. (MappingParam - CountParam)
If any constructors have the same MappingScore, select the one with more parameters.

Edge case: If any constructors have the same equal MappingScore and equal count of params select first.

Example:


Source
{
	A 
}

Destination
{
	new ()     // MappingScore = 0; ParamCount = 0;
	new (A)  // MappingScore  = 0; ParamCount = 1; <- select this max Param
}

Destination
{
	new ()         // MappingScore = 0; ParamCount = 0; <- select this max MappingScore 
	new (A,В)   // MappingScore  = -1; ParamCount = 1; 
}

Destination
{
	new (A)       // MappingScore = 0; ParamCount = 0; <- select this max MappingScore 
	new (A,В)    // MappingScore  = -1; ParamCount = 2; 
}

Edge case:


Destination
{
	new (A,B)     // MappingScore = -1; ParamCount = 1; <- select this max MappingScore 
	new (A,C)    // MappingScore  = -1; ParamCount = 1; 
}

Activity

  1. stagep commented on Mar 26, 2026

    @stagep

    If I understand correctly, select the ctor that has the most parameters that match the source properties. In an edge case, with a tie on the number, you are going with the first ctor based on alphanumeric sorting. Seems more logical then the logic of the person who created the ctors on the destination object.

  2. DocSvartz commented on Mar 26, 2026

    @DocSvartz
    ContributorAuthor

    @stagep

    select the ctor that has the most parameters that match the source properties.

    This algorithm is use in 7.4.0, but it has one problem.
    In this case, it won't select anything because nothing matches.

    Source
    {
    	A 
    }
    
    Destination
    {
    	new (F)   
    	new (B,C)  
    }
    

    That's why there should be two criteria = MaxMatched && MinUnmatched. (But in this interpretation it is much more difficult to calculate.)

    In my opinion, it's safer to activate a constructor with a one parameter than with two. Because we can't actually know whether the constructor is capable of correctly handling the default value. 😂

    *The letters are not for alphabetical order, but simply to show that these are parameters with different or matched names

  3. stagep commented on Mar 26, 2026

    @stagep

    So in the edge case example that you had

    Destination
    {
    	new (A,B)     // MappingScore = -1; ParamCount = 1; <- select this max MappingScore 
    	new (A,C)    // MappingScore  = -1; ParamCount = 1; 
    }
    

    either ctor could have been used.

    The better question is if we have properties A and B in source and we have ctor A, ctor B, ctor A C, ctor B,C, what ctor would you use?

  4. DocSvartz commented on Mar 26, 2026

    @DocSvartz
    ContributorAuthor

    ctor A or ctor B, depending on which one was written first in the source code.
    Apparently, this is how typeof(Test).GetConstructors() works.

    But I'm not sure maybe it sorts is alphabetically.

  5. DocSvartz commented on Mar 26, 2026

    @DocSvartz
    ContributorAuthor

    I was, of course, referring to .GetConstructors(). 😑
    You could, of course, add alphabetical sorting, but I don't really see the point.
    It doesn't reduce the risk of non-operability, plus there's added extra costs of additional sorting.🤔

  6. stagep commented on Mar 26, 2026

    @stagep

    Being nondeterministic within Mapster is fine. Don't add overhead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions