Mapster无法自动映射Guid与自定义Id类型问题求助
Mapster映射含隐式转换的自定义Id类型时失效问题解决
问题说明
定义了包含私有Guid字段、带参数校验的构造函数,以及Guid与Id双向隐式转换操作符的Id类;同时有两个类C1(使用Guid类型的Id属性)和C2(使用Id类型的Id属性)。使用Mapster默认映射C1到C2时,会触发Id构造函数的参数校验异常(传入了空Guid),但手动通过隐式转换赋值完全正常。另外发现,若将Id类中的Value()方法改为只读属性public Guid Value => _value,映射就能正常工作。
重现代码
public class Id { private readonly Guid _value; public Id(Guid value) { if (value == Guid.Empty) throw new ArgumentException("Id cannot be empty", nameof(value)); _value = value; } // 改为该属性时映射正常 // public Guid Value => _value; public Guid Value() => _value; public static implicit operator Guid(Id id) => id._value; public static implicit operator Id(Guid guid) => new Id(guid); } public class C1 { public Guid Id { get; set; } } public class C2 { public Id Id { get; set; } } // 测试代码 var c1 = new C1 { Id = Guid.NewGuid() }; try { var c2 = c1.Adapt<C2>(); // 此处抛出ArgumentException Console.WriteLine("映射成功"); } catch (Exception ex) { Console.WriteLine($"映射失败:{ex.Message}"); } // 手动转换正常 var manualC2 = new C2 { Id = c1.Id }; Console.WriteLine("手动转换成功");
原因分析
Mapster默认映射逻辑会优先尝试通过目标类型的构造函数创建实例,而非直接使用定义的隐式转换操作符。对于Id类,Mapster检测到其有接收Guid参数的构造函数后,会尝试为该构造函数参数寻找匹配值,但未正确识别到可以通过隐式转换将C1.Id直接赋值给C2.Id,反而错误地传入了默认的空Guid,触发构造函数的非空校验。
当添加public Guid Value => _value只读属性时,Mapster会通过属性名称匹配(源Id对应目标Value),完成值的传递,进而间接触发隐式转换逻辑,所以映射正常。
解决方案
方案1:全局配置隐式转换规则
告诉Mapster优先使用已定义的隐式转换来处理Guid和Id之间的映射:
TypeAdapterConfig<Guid, Id>.NewConfig().UseImplicitConversion(); TypeAdapterConfig<Id, Guid>.NewConfig().UseImplicitConversion();
配置完成后,默认的Adapt方法就能正常工作,无需修改其他代码。
方案2:指定单个映射的字段转换逻辑
针对C1到C2的映射,明确指定Id字段的转换方式:
TypeAdapterConfig<C1, C2>.NewConfig() .Map(dest => dest.Id, src => (Id)src.Id);
方案3:使用只读属性适配Mapster的默认映射
如你发现的,将Id类中的Value()方法改为只读属性:
public class Id { private readonly Guid _value; public Id(Guid value) { if (value == Guid.Empty) throw new ArgumentException("Id cannot be empty", nameof(value)); _value = value; } public Guid Value => _value; public static implicit operator Guid(Id id) => id._value; public static implicit operator Id(Guid guid) => new Id(guid); }
Mapster会通过属性匹配自动完成值的映射,无需额外配置。
内容的提问来源于stack exchange,提问作者Dario Griffo
相关产品推荐
相关产品推荐

