Mapster icon indicating copy to clipboard operation
Mapster copied to clipboard

Mapping Properties of different types, No default constructor for type 'CultureInfo', please use 'ConstructUsing' or 'MapWith'

Open codelovercc opened this issue 1 year ago • 3 comments

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?

codelovercc avatar Apr 08 '23 15:04 codelovercc

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>() ;

JDCain avatar Aug 16 '23 18:08 JDCain

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");

 }


DocSvartz avatar Oct 13 '23 12:10 DocSvartz