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

AutoMapper能否映射属性不全的对象并区分null的两种成因?

区分AutoMapper映射中显式Null与未设置属性的Null

AutoMapper本身无法直接区分这两种Null情况——它仅处理对象的当前属性值,无法获取属性是否被显式赋值的元数据。要实现需求,必须结合C#的反序列化跟踪或动态对象解析,记录属性的赋值状态后再在映射逻辑中利用这些状态区分。

方案一:反序列化时跟踪已设置属性,结合AutoMapper处理

步骤1:修改Foo类,添加属性跟踪集合

给Foo类添加一个忽略序列化的集合,用于记录哪些属性在反序列化时被赋值:

class Foo
{
    public string Property1 { get; set; }
    public string Property2 { get; set; }
    public string Property3 { get; set; }
    
    [JsonIgnore]
    public HashSet<string> SetProperties { get; } = new HashSet<string>();
}

步骤2:自定义Json.NET解析器,跟踪属性赋值

创建自定义的ContractResolver,在反序列化时记录每个被赋值的属性:

public class TrackingContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        
        if (member.DeclaringType == typeof(Foo) && property.PropertyName != nameof(Foo.SetProperties))
        {
            var originalSetter = property.ValueProvider;
            property.ValueProvider = new TrackingValueProvider(originalSetter, member.Name);
        }
        
        return property;
    }

    private class TrackingValueProvider : IValueProvider
    {
        private readonly IValueProvider _originalProvider;
        private readonly string _propertyName;

        public TrackingValueProvider(IValueProvider originalProvider, string propertyName)
        {
            _originalProvider = originalProvider;
            _propertyName = propertyName;
        }

        public void SetValue(object target, object value)
        {
            _originalProvider.SetValue(target, value);
            if (target is Foo foo)
            {
                foo.SetProperties.Add(_propertyName);
            }
        }

        public object GetValue(object target)
        {
            return _originalProvider.GetValue(target);
        }
    }
}

步骤3:使用自定义解析器反序列化

var settings = new JsonSerializerSettings
{
    ContractResolver = new TrackingContractResolver()
};
var toMap = JsonConvert.DeserializeObject<Foo>("{Property1: \"myproperty\", Property2: null }", settings);

步骤4:配置AutoMapper映射,区分两种Null情况

可以通过AfterMap添加标记,或者直接在映射时设置不同的默认值:

// 方案A:给Bar添加显式设置标记
CreateMap<Foo, Bar>()
    .ForMember(dest => dest.Item1, opt => opt.MapFrom(src => src.Property1))
    .ForMember(dest => dest.Item2, opt => opt.MapFrom(src => src.Property2))
    .ForMember(dest => dest.Item3, opt => opt.MapFrom(src => src.Property3))
    .AfterMap((src, dest) =>
    {
        if (src.SetProperties.Contains(nameof(Foo.Property1)))
            dest.ExplicitlySetItems.Add(nameof(Bar.Item1));
        if (src.SetProperties.Contains(nameof(Foo.Property2)))
            dest.ExplicitlySetItems.Add(nameof(Bar.Item2));
        if (src.SetProperties.Contains(nameof(Foo.Property3)))
            dest.ExplicitlySetItems.Add(nameof(Bar.Item3));
    });

// 方案B:给未设置的属性指定非Null默认值
CreateMap<Foo, Bar>()
    .ForMember(dest => dest.Item1, opt => opt.MapFrom(src => src.Property1))
    .ForMember(dest => dest.Item2, opt => opt.MapFrom(src => src.Property2))
    .ForMember(dest => dest.Item3, opt => 
        opt.MapFrom(src => src.SetProperties.Contains(nameof(Foo.Property3)) ? src.Property3 : string.Empty));

方案二:直接使用JObject动态映射

如果不需要强类型的Foo,可以直接用JObject解析JSON,通过检查键是否存在来区分:

步骤1:解析JSON为JObject

var jObject = JObject.Parse("{Property1: \"myproperty\", Property2: null }");

步骤2:配置AutoMapper映射JObject到Bar

CreateMap<JObject, Bar>()
    .ForMember(dest => dest.Item1, opt => opt.MapFrom(src => src["Property1"]?.Value<string>()))
    .ForMember(dest => dest.Item2, opt => opt.MapFrom(src => src["Property2"]?.Value<string>()))
    .ForMember(dest => dest.Item3, opt => 
        opt.MapFrom(src => src.ContainsKey("Property3") ? src["Property3"]?.Value<string>() : string.Empty))
    .AfterMap((src, dest) =>
    {
        dest.ExplicitlySetItems.Add(nameof(Bar.Item1)); // Property1在JSON中存在
        if (src.ContainsKey("Property2")) dest.ExplicitlySetItems.Add(nameof(Bar.Item2));
        if (src.ContainsKey("Property3")) dest.ExplicitlySetItems.Add(nameof(Bar.Item3));
    });

内容的提问来源于stack exchange,提问作者Esben Rune Hansen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 03:24:21