Mapster
Mapster copied to clipboard
Mapping Properties of different types, No default constructor for type 'CultureInfo', please use 'ConstructUsing' or 'MapWith'
Hi,
I use Mapster with version 7.3.0 and .Net 7.0.1
I have two classes.
public class Entity
{
public Guid Id { get; set; }
public string Content { get; set; } = default!;
public string Note { get; set; } = default!;
public CultureInfo CultureInfo { get; set; } = default!;
}
public class Dto
{
[Required, StringLength(64)]
public string Id { get; set; } = default!;
[Required, StringLength(4096)]
public string Content { get; set; } = default!;
[Required, StringLength(1024)]
public string Note { get; set; } = default!;
[Required]
public string CultureName { get; set; } = default!;
}
And with mapster config
TypeAdapterConfig<Dto, Entity>.NewConfig()
.Map(entity => entity.CultureInfo, dto => CultureInfo.GetCultureInfo(dto.CultureName));
TypeAdapterConfig<Entity, Dto>.NewConfig()
.Map(dto => dto.CultureName, entity => entity.CultureInfo.Name);
Now execute this code
//Mapster configuration is applied.
var dto = new Dto
{
Id = Guid.NewGuid().ToString(),
Content = "this is a test content",
Note = "for test",
CultureName = "zh-CN"
};
var mLocal = dto.Adapt<Entity>();
var mLocal = dto.Adapt<Entity>(); throws a Mapster.CompileException: Error while compiling.
Mapster.CompileException: Error while compiling
Mapster.CompileException
Error while compiling
source=MindOcean.Models.Common.MessageTemplateLocalizerDto
destination=MindOcean.Data.Entities.MessageTemplateLocalizer
type=Map
at Mapster.TypeAdapterConfig.CreateMapExpression(CompileArgument arg)
at Mapster.TypeAdapterConfig.CreateMapExpression(TypeTuple tuple, MapType mapType)
at Mapster.TypeAdapterConfig.CreateDynamicMapExpression(TypeTuple tuple)
at Mapster.TypeAdapterConfig.<GetDynamicMapFunction>b__66_0[TDestination](TypeTuple tuple)
at Mapster.TypeAdapterConfig.<>c__DisplayClass55_0`1.<AddToHash>b__0(TypeTuple types)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Mapster.TypeAdapterConfig.AddToHash[T](ConcurrentDictionary`2 hash, TypeTuple key, Func`2 func)
at Mapster.TypeAdapterConfig.GetDynamicMapFunction[TDestination](Type sourceType)
at Mapster.TypeAdapter.Adapt[TDestination](Object source, TypeAdapterConfig config)
at Mapster.TypeAdapter.Adapt[TDestination](Object source)
at MindOcean.Test.UnitTest.MapsterTester.TestTwoWay() in /Test/MapsterTester.cs:line 71
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
Mapster.CompileException
Error while compiling
source=System.Globalization.CultureInfo
destination=System.Globalization.CultureInfo
type=Map
at Mapster.TypeAdapterConfig.CreateMapExpression(CompileArgument arg)
at Mapster.TypeAdapterConfig.CreateInlineMapExpression(Type sourceType, Type destinationType, MapType mapType, CompileContext context, MemberMapping mapping)
at Mapster.Adapters.BaseAdapter.CreateAdaptExpressionCore(Expression source, Type destinationType, CompileArgument arg, MemberMapping mapping, Expression destination)
at Mapster.Adapters.BaseAdapter.CreateAdaptExpression(Expression source, Type destinationType, CompileArgument arg, MemberMapping mapping, Expression destination)
at Mapster.Adapters.ClassAdapter.CreateInlineExpression(Expression source, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateInlineExpressionBody(Expression source, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateExpressionBody(Expression source, Expression destination, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateAdaptFunc(CompileArgument arg)
at Mapster.TypeAdapterConfig.CreateMapExpression(CompileArgument arg)
System.InvalidOperationException
No default constructor for type 'CultureInfo', please use 'ConstructUsing' or 'MapWith'
at Mapster.Adapters.BaseAdapter.CreateInstantiationExpression(Expression source, Expression destination, CompileArgument arg)
at Mapster.Adapters.ClassAdapter.CreateInstantiationExpression(Expression source, Expression destination, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateInstantiationExpression(Expression source, CompileArgument arg)
at Mapster.Adapters.ClassAdapter.CreateInlineExpression(Expression source, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateInlineExpressionBody(Expression source, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateExpressionBody(Expression source, Expression destination, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateAdaptFunc(CompileArgument arg)
at Mapster.TypeAdapterConfig.CreateMapExpression(CompileArgument arg)
No default constructor for type 'CultureInfo', please use 'ConstructUsing' or 'MapWith'
I tried use MapWith and it worked.
TypeAdapterConfig<Dto, Entity>.NewConfig()
.MapWith(dto => new Entity
{
CultureInfo = CultureInfo.GetCultureInfo(dto.CultureName),
Id = Guid.Parse(dto.Id),
Content = dto.Content,
Note = dto.Note,
});
TypeAdapterConfig<Entity, Dto>.NewConfig()
.Map(dto => dto.CultureName, entity => entity.CultureInfo.Name);
This configuration didn't work.
TypeAdapterConfig<Dto, Entity>.NewConfig()
.Map(entity => entity.CultureInfo, dto => CultureInfo.GetCultureInfo(dto.CultureName));
dto => CultureInfo.GetCultureInfo(dto.CultureName)
should work to create an instance of CultureInfo
with out a constructor.
Is there something I missed or is this a bug?
I was getting the same error when trying to use the code generator for the same type of thing when using a Geometery
type from a 3rd party library. I was able to get it to work with this:
TypeAdapterConfig<Geometry, Geometry>.NewConfig()
.ConstructUsing(x => Geometry.DefaultFactory.CreateGeometry(x));
config.GenerateMapper("[name]Mapper")
.ForType<Agency>() ;
Hello, It Working with config
[TestMethod]
public void MappingInsiderCultureInfo()
{
TypeAdapterConfig<string, CultureInfo>.NewConfig()
.MapWith(str=> new CultureInfo(str));
TypeAdapterConfig<Dto, Entity>.NewConfig()
.Map(entity => entity.CultureInfo, dto => dto.CultureName);
TypeAdapterConfig<Entity Dto>.NewConfig()
.Map(dto => dto.CultureName, entity => entity.CultureInfo.Name);
var dto = new Dto
{
Id = "edcd0ab3-a949-4127-83c0-8a33f4108f09",
Content = "this is a test content",
Note = "for test",
CultureName = "zh-CN"
};
var mLocal = dto.Adapt<Entity>();
mLocal.Id.ToString().ShouldBe("edcd0ab3-a949-4127-83c0-8a33f4108f09");
mLocal.CultureInfo.Name.ShouldBe("zh-CN");
mLocal.Content.ShouldBe("this is a test content");
mLocal.Note.ShouldBe("for test");
}