You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Automapper通用映射需求:仅映射非默认值属性

用AutoMapper实现「仅映射源对象已修改属性」的通用方案

我完全理解你的需求:只有当Source对象的属性值偏离了它自身的默认值时,才将该值映射到Destination;如果源属性还是默认值,就保留Destination自己的默认值。AutoMapper本身没有直接的内置开关,但我们可以通过自定义条件判断来完美实现这个逻辑,下面给你一步步拆解:

1. 先确认我们的源和目标类(你的现有代码)

public class Source { 
    public string Foo { get; set; } = "Foo"; 
    public string Bar { get; set; } = "Bar"; 
} 

public class Destination { 
    public string Foo { get; set; } = "Foo of Destination"; 
    public string Bar { get; set; } = "Bar of Destination"; 
}

2. 核心:配置AutoMapper的条件映射

关键思路是:为每个属性设置映射条件——只有当源属性的值不等于它的默认值时,才执行映射操作。我们可以先创建一个Source的默认实例,用来做对比基准。

配置代码如下:

var config = new MapperConfiguration(cfg =>
{
    // 创建一个Source的默认实例,作为判断"是否修改"的基准
    var defaultSource = new Source();
    
    cfg.CreateMap<Source, Destination>()
        // 给Foo属性加映射条件
        .ForMember(dest => dest.Foo, opt =>
        {
            // 只有当源的Foo不是默认值时,才映射
            opt.Condition(src => src.Foo != defaultSource.Foo);
            opt.MapFrom(src => src.Foo);
        })
        // 给Bar属性加映射条件
        .ForMember(dest => dest.Bar, opt =>
        {
            opt.Condition(src => src.Bar != defaultSource.Bar);
            opt.MapFrom(src => src.Bar);
        });
});

// 验证配置是否正确(推荐加上,避免配置错误)
config.AssertConfigurationIsValid();

// 创建Mapper实例
var _mapper = config.CreateMapper();

3. 验证你的测试用例

现在你的三个测试用例都能完美通过:

测试用例1:ChangeAllProperties(源对象全默认)

当Source是默认状态时,所有属性都不会触发映射,Destination保留自己的默认值:

[TestMethod] 
public void ChangeAllProperties() { 
    var source = new Source(); 
    var destination = _mapper.Map<Destination>(source); 
    var defaultDestination = new Destination(); 
    Assert.AreEqual(destination.Bar, defaultDestination.Bar); // 结果:目标默认值"Bar of Destination"
    Assert.AreEqual(destination.Foo, defaultDestination.Foo); // 结果:目标默认值"Foo of Destination"
} 

测试用例2:ChangeDefaultProperty(仅修改Bar)

只有Bar被修改了,所以只有Bar会被映射,Foo依然保留目标的默认值:

[TestMethod] 
public void ChangeDefaultProperty() { 
    var source = new Source(); 
    source.Bar = "Custom Bar!"; 
    var destination = _mapper.Map<Destination>(source); 
    var defaultDestination = new Destination(); 
    Assert.AreEqual(destination.Bar, source.Bar); // 结果:源的自定义值"Custom Bar!"
    Assert.AreEqual(destination.Foo, defaultDestination.Foo); // 结果:目标默认值"Foo of Destination"
} 

测试用例3:AlLChanged(两个属性都修改)

两个属性都偏离了默认值,所以都会被映射到Destination:

[TestMethod] 
public void AlLChanged() { 
    var source = new Source(); 
    source.Foo = "Custom Foo!"; 
    source.Bar = "Custom Bar!"; 
    var destination = _mapper.Map<Destination>(source); 
    Assert.AreEqual(destination.Bar, source.Bar); // 结果:"Custom Bar!"
    Assert.AreEqual(destination.Foo, source.Foo); // 结果:"Custom Foo!"
}

4. 进阶:通用化处理(避免逐个配置属性)

如果你的类有很多属性,一个个写ForMember太繁琐,可以用反射自动为所有属性添加条件:

var config = new MapperConfiguration(cfg =>
{
    var defaultSource = Activator.CreateInstance<Source>();
    var sourceProps = typeof(Source).GetProperties(BindingFlags.Public | BindingFlags.Instance);
    
    cfg.CreateMap<Source, Destination>()
        .ForAllMembers(opt =>
        {
            // 找到当前属性在Source中的对应属性
            var sourceProp = sourceProps.First(p => p.Name == opt.DestinationMember.Name);
            // 获取该属性的默认值
            var defaultValue = sourceProp.GetValue(defaultSource);
            // 设置条件:只有当源属性值不等于默认值时才映射
            opt.Condition((src, dest, srcValue) => !Equals(srcValue, defaultValue));
        });
});

这个方案会自动遍历所有属性,统一添加映射条件,适合属性较多的场景。


内容的提问来源于stack exchange,提问作者oiBio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 11:07:51