Skip to content

Conversation

@samusaran
Copy link

@samusaran samusaran commented Jan 16, 2026

Add support for Shallow Cloning

Description

The current behaviour of Mapperly when mapping between same types is either to return the original instance, or to perform a deep clone of the entire object graph.

Another use case lies in the middle of those two solutions: Shallow Cloning.

Shallow cloning an object allows a user to clone an object at the first level, while keeping all the references to other reference types unchanged. If a user needs some references to be handled differently, they can still use a user mapping on those specific properties.

This feature also aligns to the default behaviour of Automapper, and this could help users to more easily migrate from Automapper to Mapperly.

Fixes #2113

Checklist

  • The existing code style is followed
  • The commit message follows our guidelines
  • Performed a self-review of my code
  • Hard-to-understand areas of my code are commented
  • The documentation is updated (as applicable)
  • Unit tests are added/updated
  • Integration tests are added/updated (as applicable, especially if feature/bug depends on roslyn or framework version in use)

@samusaran
Copy link
Author

samusaran commented Jan 16, 2026

@latonz I would continue the discussion here.

As stated in the github issue #2113, another solution would be to deprecate UseShallowCloning in favour of a single CloningBehaviour enum, to avoid having conflicting configuration between shallow and deep cloning.

At least from a user perspective, I find this solution to be less confusing.

@robertjak
Copy link

We are eagerly expecting this feature!

@samusaran
Copy link
Author

Hi @latonz , sorry for the delay. I've managed to work on the feature but i've found a small issue, but maybe you can help me.

The first iteration (where everything worked fine) used a single attribute on the mapping methods to specify that the mapping should use the Shallow Clone approach.

The thing is that when moving that attribute to the Mapper itself, it's seems to me that it's impossible to distinguish the Shallow Clone from the Deep Clone.

Let's take the following example:

class A 
{ 
   public int Value { get; set; } 
   public List<string> List { get; set; } 
}

[Mapper(CloningBehaviour = CloningBehaviour.ShallowClone)]
public static partial class ShallowCloningMapper
{
   public static partial A Copy(A src);
}

What we are asking is to shallow clone A, but since the ShallowClone behaviour is applied at the mapping level, I get "shallow clones" of everything, resulting in a strange deep clone. This is because MappingBuilder iterates on all properties of A.

In this case the resulting mapping is the following:

                var target = new global::A();
                target.Value = source.Value;
                target.List = global::System.Linq.Enumerable.ToList(source.List);
                return target;

while the expected is

                var target = new global::A();
                target.Value = source.Value;
                target.List = source.List;
                return target;

Do you have any suggestions on how to handle this?

This all works if I roll back to the previous behaviour of "DeepCloning at mapper level, ShallowCloning at method level"

Alessandro Losi added 3 commits February 3, 2026 12:12
The implementation is currently not working because applying ShallowClone to the Mapper level results in a "recursive shallow clone" which defeats the purpose of the shallow clone itself.
@samusaran samusaran force-pushed the shallow-clone-for-same-types branch from 4057136 to 209d92f Compare February 3, 2026 11:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Give the possibility to clone objects without UseDeepCloning

2 participants