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

在C#中如何通过字符串/变量动态选择类型简化映射逻辑?

解决Umbraco块类型动态映射的方案

针对你遇到的30-40种CMS块类型映射冗余问题,这里提供两种实用的解决思路,替代繁琐的switch语句:


方法一:反射调用泛型Map方法

核心思路是提前维护块别名→目标类型的映射字典,再通过反射动态调用_umbracoMapper.Map<T>泛型方法。

步骤1:初始化类型映射字典

在类的构造函数或静态区域初始化字典(确保别名和类型一一对应):

private readonly Dictionary<string, Type> _blockTypeMap = new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase)
{
    { "Heading", typeof(Heading) },
    { "Carousel", typeof(Carousel) },
    // 逐一添加剩余的块类型映射
};

步骤2:动态映射实现

编写通用的映射方法,通过反射获取并调用泛型Map:

public object MapBlock(dynamic block)
{
    if (!_blockTypeMap.TryGetValue(block.Type, out var targetType))
    {
        throw new ArgumentException($"未识别的块类型:{block.Type}");
    }

    // 获取UmbracoMapper的Map<T>泛型方法定义
    var mapMethod = _umbracoMapper.GetType()
        .GetMethod("Map", new[] { typeof(object) });
    
    if (mapMethod == null)
    {
        throw new InvalidOperationException("无法在UmbracoMapper上找到Map方法");
    }

    // 创建指定目标类型的泛型方法实例
    var genericMapMethod = mapMethod.MakeGenericMethod(targetType);
    // 执行映射并返回结果
    return genericMapMethod.Invoke(_umbracoMapper, new[] { block });
}

这种方法代码量少,无需额外创建类,适合快速落地;缺点是反射调用有轻微性能损耗(但对于30-40种类型的场景可以忽略)。


方法二:工厂模式+类型安全映射

如果追求类型安全、可测试性和扩展性,推荐使用工厂模式,为每个块类型单独实现映射逻辑。

步骤1:定义映射接口

创建统一的块映射接口:

public interface IBlockMapper
{
    object Map(dynamic block);
}

步骤2:实现单个块的映射类

为每个块类型编写对应的映射实现(以Heading为例):

public class HeadingBlockMapper : IBlockMapper
{
    private readonly IUmbracoMapper _umbracoMapper;

    public HeadingBlockMapper(IUmbracoMapper umbracoMapper)
    {
        _umbracoMapper = umbracoMapper;
    }

    public object Map(dynamic block)
    {
        return _umbracoMapper.Map<Heading>(block);
    }
}

步骤3:注册映射类到DI

在项目的DI注册代码中,添加所有映射类的注册:

services.AddTransient<HeadingBlockMapper>();
services.AddTransient<CarouselBlockMapper>();
// 注册剩余的块映射类

步骤4:实现映射工厂

创建工厂类,根据块别名获取对应的映射器并执行映射:

public class BlockMapperFactory
{
    private readonly IServiceProvider _serviceProvider;
    private readonly Dictionary<string, Type> _mapperTypeMap = new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase)
    {
        { "Heading", typeof(HeadingBlockMapper) },
        { "Carousel", typeof(CarouselBlockMapper) },
        // 匹配所有块别名与对应映射类
    };

    public BlockMapperFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public object MapBlock(dynamic block)
    {
        if (!_mapperTypeMap.TryGetValue(block.Type, out var mapperType))
        {
            throw new ArgumentException($"未识别的块类型:{block.Type}");
        }

        var mapper = (IBlockMapper)_serviceProvider.GetService(mapperType);
        return mapper?.Map(block);
    }
}

这种方法的优势是类型安全、易于单元测试,后续新增块类型只需添加对应映射类和注册项即可;缺点是需要编写较多的映射类文件。


后续处理说明

两种方法返回的都是具体的块模型实例(如Heading、Carousel),你可以通过模式匹配来处理不同类型的结果:

var mappedBlock = MapBlock(block);
switch (mappedBlock)
{
    case Heading heading:
        // 处理Heading逻辑
        break;
    case Carousel carousel:
        // 处理Carousel逻辑
        break;
    // 其他类型
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 06:01:32