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

如何通过Automapper根据源类型属性值动态映射目标类型?

How to Implement Dynamic Mapping with AutoMapper Based on a Property Value (Animal → CatDto/DogDto and Reverse)

Absolutely, you can implement dynamic mapping in AutoMapper to route Animal instances to CatDto or DogDto based on the AnimalType property — and this approach works even with nested types, solving the issue you mentioned where manual if/switch logic fails for nested mappings. Here's a step-by-step implementation:

Step 1: Configure the AutoMapper Profile

First, create a profile that defines the dynamic mapping logic, along with specific mappings for each type pair and reverse mappings:

public enum EAnimalType { Cat = 1, Dog = 2 }

public class Animal { 
    public EAnimalType AnimalType { get; set; } 
    public int Age { get; set; }
    // Optional: Nested property to test nested mapping
    public List<Animal> Offspring { get; set; }
}

public abstract class AnimalDto { 
    public int Age { get; set; }
    // Optional: Nested property to test nested mapping
    public List<AnimalDto> Offspring { get; set; }
}

public class CatDto : AnimalDto {}
public class DogDto : AnimalDto {}

public class AnimalProfile : Profile
{
    public AnimalProfile()
    {
        // Core dynamic mapping: Animal → AnimalDto (routes to Cat/DogDto)
        CreateMap<Animal, AnimalDto>()
            .ConvertUsing((source, _, context) =>
            {
                return source.AnimalType switch
                {
                    EAnimalType.Cat => context.Mapper.Map<CatDto>(source),
                    EAnimalType.Dog => context.Mapper.Map<DogDto>(source),
                    _ => throw new InvalidOperationException($"Unsupported animal type: {source.AnimalType}")
                };
            });

        // Explicit mappings for each concrete type pair (ensures property mapping works)
        CreateMap<Animal, CatDto>();
        CreateMap<Animal, DogDto>();

        // Reverse mapping: CatDto → Animal (sets AnimalType automatically)
        CreateMap<CatDto, Animal>()
            .ForMember(dest => dest.AnimalType, opt => opt.MapFrom(_ => EAnimalType.Cat));

        // Reverse mapping: DogDto → Animal (sets AnimalType automatically)
        CreateMap<DogDto, Animal>()
            .ForMember(dest => dest.AnimalType, opt => opt.MapFrom(_ => EAnimalType.Dog));
    }
}

Key Details:

  • ConvertUsing for Dynamic Routing: This method lets us fully control the conversion process. We use a switch expression to select the correct DTO type based on AnimalType, then delegate to AutoMapper's built-in mapping for the concrete type pair.
  • Explicit Concrete Mappings: We need separate CreateMap<Animal, CatDto> and CreateMap<Animal, DogDto> entries so AutoMapper handles automatic property mapping (like copying the Age property) without manual code.
  • Reverse Mapping: For each DTO subclass, we explicitly set the AnimalType property to the corresponding enum value, so mapping back to Animal is straightforward.

Step 2: Test the Mapping

Initialize AutoMapper and verify both forward and reverse mappings work as expected:

// Initialize AutoMapper with our profile
var config = new MapperConfiguration(cfg => cfg.AddProfile<AnimalProfile>());
var mapper = config.CreateMapper();

// Test forward mapping (Animal → CatDto/DogDto)
var cat = new Animal { AnimalType = EAnimalType.Cat, Age = 3 };
AnimalDto catDto = mapper.Map<AnimalDto>(cat);
Console.WriteLine(catDto.GetType().Name); // Output: CatDto
Console.WriteLine(catDto.Age); // Output: 3

var dog = new Animal { AnimalType = EAnimalType.Dog, Age = 5 };
AnimalDto dogDto = mapper.Map<AnimalDto>(dog);
Console.WriteLine(dogDto.GetType().Name); // Output: DogDto
Console.WriteLine(dogDto.Age); // Output: 5

// Test nested mapping (if you added the Offspring property)
var parentCat = new Animal { 
    AnimalType = EAnimalType.Cat, 
    Age = 4,
    Offspring = new List<Animal> { new Animal { AnimalType = EAnimalType.Cat, Age = 1 } }
};
AnimalDto parentCatDto = mapper.Map<AnimalDto>(parentCat);
Console.WriteLine(parentCatDto.Offspring[0].GetType().Name); // Output: CatDto

// Test reverse mapping (CatDto/DogDto → Animal)
var catDtoReverse = new CatDto { Age = 2 };
Animal catReverse = mapper.Map<Animal>(catDtoReverse);
Console.WriteLine(catReverse.AnimalType); // Output: Cat
Console.WriteLine(catReverse.Age); // Output: 2

var dogDtoReverse = new DogDto { Age = 6 };
Animal dogReverse = mapper.Map<Animal>(dogDtoReverse);
Console.WriteLine(dogReverse.AnimalType); // Output: Dog
Console.WriteLine(dogReverse.Age); // Output: 6

Why This Fixes Nested Mapping Issues

Unlike manual if/switch logic you tried earlier, this approach integrates directly with AutoMapper's recursive mapping system. When mapping nested properties (like Offspring), AutoMapper will automatically apply the same dynamic routing logic to each nested Animal instance, ensuring they're mapped to the correct DTO subclass. No extra code is needed for nested types — the profile configuration handles it all.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:18:15