MapsterMapper / MapsterMapper/Mapster

Feat: more powerful Attribute-based configuration

Open
#360 0 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

config features feature request
Dominant language
C#
Stars
5.2k
Forks
410
Avg merge
2d 12h
Merged PRs (30d)
6

Description

It would be nice if we could use attributes to define any (or most...) aspects of mapping -- and if we could derive our own attributes to do that.

### Use case
I want to be able to easily say, with an attribute, that a property is mapped only if another property has a specific value.

If I was doing this in code, it would be:
```cs
config.Map(target => target.Prop, src => src.Prop, src => src.Other == SentinelValue);
```

Instead, I wrote an attribute to configure this aspect:
```cs
class SourceDto
{
public string Other { get; set; }
[AdaptNullUnless(nameof(Other), SentinelValue)]
public string Prop { get; set; }
}
```

Of course, because this attribute is unknown to Mapster, I also had to create an `IRegister` implementation that configures those mappings automatically using reflection.

It would be nice if that last part was not required.

### Suggestion
Similar to other frameworks that use Attributes as an alternative configuration (I'm thinking Grace IoC here), maybe Mapster could provide a base attribute class:

```cs
// Provided my Mapster
abstract class MapsterPropertyAttribute : Attribute
{
public void abstract Map(PropertyInfo property, TypeAdapterSetter config);
}
```

Maspter would then find any attribute derived from `MapsterPropertyAttribute` when building a mapping and invoke `Map` on them.

With this, users could build their own attributes and apply them without any other discovery step.

My example use case would be entierly contained in this attribute:
```cs
public class AdaptNullUnlessAttribute : MapsterPropertyAttribute
{
private string other;
private object value;

public AdaptNullUnlessAttribute(string other, object value)
{
this.other = other;
this.value = value;
}

public override void Map(PropertyInfo prop, TypeAdapterSetter config)
{
config.Settings.Resolvers.Add(new InvokerModel
{
// This assumes same name, maybe Mapster should pass the config so far to this method,
// esp. the target name if AdaptMember was also used.
DestinationMemberName = p.Name,
SourceMemberName = p.Name,
Condition = Expression.Lambda(...), // Removed for conciseness
});
}
}
```

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue names no repository files or tests. Start by tracing existing attribute handling and IRegister configuration around TypeAdapterSetter, PropertyInfo, and InvokerModel; done would mean a derived attribute can be discovered and affect a mapping without a separate registration step.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
developer-experience
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.