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

.NET中AutoMapper列表转扁平对象避免索引越界的方法

解决AutoMapper列表转扁平对象的索引越界问题

类定义

public class Container
{
    public List<Product> Products;
}

public class Product
{
    public string Name;
    public string Colour;
}
    
public class NewClass
{
    public string Name1;
    public string Colour1;
    public string Name2;
    public string Colour2;
    public string Name3;
    public string Colour3;
}

问题说明

需要将Container映射到NewClass,已知Products列表元素数量最多3个,但直接通过索引访问列表元素的AutoMapper配置会因为列表长度不足(比如只有1或2个元素)抛出索引越界异常。原错误配置存在语法错误和索引访问风险:

// 原错误配置示例
cfg.CreateMap<Container, NewClass>()
    .ForMember(d => d.Name1, 
        opt => opt.MapFrom(src => src.Products[0].Name))
    .ForMember(d => d.Name2, 
        opt => opt.MapFrom(src => src.Products[1].Name))
    .ForMember(d => d.Name3, 
        opt => opt.MapFrom(src => src.Products[2].Name));

正确映射方法

方法1:用ElementAtOrDefault安全访问(最简洁)

利用LINQ的ElementAtOrDefault方法,当索引超出列表长度时返回null,结合空值运算符?.避免空引用,直接获取属性值:

cfg.CreateMap<Container, NewClass>()
    // 映射第一个产品
    .ForMember(dest => dest.Name1, opt => opt.MapFrom(src => src.Products.ElementAtOrDefault(0)?.Name))
    .ForMember(dest => dest.Colour1, opt => opt.MapFrom(src => src.Products.ElementAtOrDefault(0)?.Colour))
    // 映射第二个产品
    .ForMember(dest => dest.Name2, opt => opt.MapFrom(src => src.Products.ElementAtOrDefault(1)?.Name))
    .ForMember(dest => dest.Colour2, opt => opt.MapFrom(src => src.Products.ElementAtOrDefault(1)?.Colour))
    // 映射第三个产品
    .ForMember(dest => dest.Name3, opt => opt.MapFrom(src => src.Products.ElementAtOrDefault(2)?.Name))
    .ForMember(dest => dest.Colour3, opt => opt.MapFrom(src => src.Products.ElementAtOrDefault(2)?.Colour));

方法2:自定义值解析器(适合复杂逻辑复用)

如果需要处理默认值或更复杂的逻辑,可以自定义值解析器,复用索引判断逻辑:

// 自定义解析器:根据索引和属性选择器获取产品属性
public class ProductPropertyResolver : IValueResolver<Container, NewClass, string>
{
    private readonly int _index;
    private readonly Func<Product, string> _propertySelector;

    public ProductPropertyResolver(int index, Func<Product, string> propertySelector)
    {
        _index = index;
        _propertySelector = propertySelector;
    }

    public string Resolve(Container source, NewClass destination, string destMember, ResolutionContext context)
    {
        if (source.Products == null || _index >= source.Products.Count)
            return null; // 也可以返回默认字符串,比如""
        return _propertySelector(source.Products[_index]);
    }
}

// 配置映射
cfg.CreateMap<Container, NewClass>()
    .ForMember(d => d.Name1, opt => opt.MapFrom(new ProductPropertyResolver(0, p => p.Name)))
    .ForMember(d => d.Colour1, opt => opt.MapFrom(new ProductPropertyResolver(0, p => p.Colour)))
    .ForMember(d => d.Name2, opt => opt.MapFrom(new ProductPropertyResolver(1, p => p.Name)))
    .ForMember(d => d.Colour2, opt => opt.MapFrom(new ProductPropertyResolver(1, p => p.Colour)))
    .ForMember(d => d.Name3, opt => opt.MapFrom(new ProductPropertyResolver(2, p => p.Name)))
    .ForMember(d => d.Colour3, opt => opt.MapFrom(new ProductPropertyResolver(2, p => p.Colour)));

方法3:直接条件判断(直观易懂)

在映射表达式里直接判断列表长度,确保索引有效后再访问元素:

cfg.CreateMap<Container, NewClass>()
    .ForMember(d => d.Name1, opt => opt.MapFrom(src => src.Products != null && src.Products.Count > 0 ? src.Products[0].Name : null))
    .ForMember(d => d.Colour1, opt => opt.MapFrom(src => src.Products != null && src.Products.Count > 0 ? src.Products[0].Colour : null))
    .ForMember(d => d.Name2, opt => opt.MapFrom(src => src.Products != null && src.Products.Count > 1 ? src.Products[1].Name : null))
    .ForMember(d => d.Colour2, opt => opt.MapFrom(src => src.Products != null && src.Products.Count > 1 ? src.Products[1].Colour : null))
    .ForMember(d => d.Name3, opt => opt.MapFrom(src => src.Products != null && src.Products.Count > 2 ? src.Products[2].Name : null))
    .ForMember(d => d.Colour3, opt => opt.MapFrom(src => src.Products != null && src.Products.Count > 2 ? src.Products[2].Colour : null));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 17:45:40