How can I make AutoMapper to map missing unmapped properties to a dictionary inside the destination object? (Like ExtensionData during serialization)
Example:
class Source
{
public int A {get;set;}
public int B {get;set;}
public int C {get;set;}
}
class Destination
{
public int A {get;set;}
public Dictionary<string, object> D {get;set;}
}
Source s = new Source { A = 1, B = 2, C = 3 };
Destination d = ... // Mapping code
Now I want the following result:
d.A ==> 1
d.D ==> {{ "B", 2 }, { "C", 3 }}
* EDIT *
In the end I am looking for a solution w/o reflection. Meaning: During setup/configuration/initialization reflection is allowed, but during the mapping itself, I do not want any delays caused by reflection.
* EDIT *
I am looking for a generic solution, just like the serializers.
AutoMapper will map property with private setter with no problem. If you want to force encapsulation, you need to use IgnoreAllPropertiesWithAnInaccessibleSetter. With this option, all private properties (and other inaccessible) will be ignored.
Yes, or you can call CreateMap<ModelClass, ViewModelClass>(). ReverseMap() .
There are a lot of possible solutions for your problem. I've create a custom value resolver for your property and it works perfectly:
public class CustomResolver : IValueResolver<Source, Destination, Dictionary<string, object>>
{
public Dictionary<string, object> Resolve(Source source, Destination destination, Dictionary<string, object> destMember, ResolutionContext context)
{
destMember = new Dictionary<string, object>();
var flags = BindingFlags.Public | BindingFlags.Instance;
var sourceProperties = typeof(Source).GetProperties(flags);
foreach (var property in sourceProperties)
{
if (typeof(Destination).GetProperty(property.Name, flags) == null)
{
destMember.Add(property.Name, property.GetValue(source));
}
}
return destMember;
}
}
How to use it?
static void Main(string[] args)
{
Mapper.Initialize(cfg => {
cfg.CreateMap<Source, Destination>()
.ForMember(dest => dest.D, opt => opt.ResolveUsing<CustomResolver>());
});
var source = new Source { A = 1, B = 2, C = 3 };
var result = Mapper.Map<Source, Destination>(source);
}
public class Source
{
public int A { get; set; }
public int B { get; set; }
public int C { get; set; }
}
public class Destination
{
public int A { get; set; }
public Dictionary<string, object> D { get; set; }
}
I like Pawel's solution because is more generic. If you want something simpler but less generic you could initialize the mapper like this:
Mapper.Initialize(cfg => {
cfg.CreateMap<Source, Destination>()
.ForMember(dest => dest.D,
opt => opt.MapFrom(r => new Dictionary<string,object>(){{ "B", r.B},{ "C", r.C}}));
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With