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

C#如何将字符串转换为数据对象及字段引用实现动态赋值

C#动态映射配置赋值实现方案

针对字符串形式的类名、属性名动态赋值需求,无需手写多层switch分支,直接使用反射+元数据缓存方案即可实现,兼顾扩展性与性能。

核心实现代码

首先实现通用的动态赋值工具类,加入缓存避免重复反射带来的性能损耗:

using System.Reflection;

public static class EntityMapper
{
    // 缓存:类名 -> 对应类型元数据
    private static readonly Dictionary<string, Type> _typeCache = new();
    // 缓存:类名.属性名 -> 对应属性元数据
    private static readonly Dictionary<string, PropertyInfo> _propertyCache = new();

    /// <summary>
    /// 动态创建实体实例并给指定属性赋值
    /// </summary>
    /// <param name="className">数据库读取的目标类名</param>
    /// <param name="propertyName">数据库读取的目标属性名</param>
    /// <param name="value">要赋值的字段值</param>
    /// <returns>赋值完成的实体实例</returns>
    /// <exception cref="ArgumentException">找不到对应类或可写属性时抛出</exception>
    public static object AssignProperty(string className, string propertyName, string value)
    {
        // 查找目标类型,优先读缓存
        if (!_typeCache.TryGetValue(className, out Type targetType))
        {
            // 扫描当前程序集的所有类匹配类名,若实体在其他程序集可加入对应程序集扫描
            targetType = Assembly.GetExecutingAssembly()
                .GetTypes()
                .FirstOrDefault(t => t.IsClass && t.Name == className);

            if (targetType == null)
                throw new ArgumentException($"未找到匹配的实体类:{className}");
            
            _typeCache.TryAdd(className, targetType);
        }

        // 创建实体实例,若需复用已有实例可跳过该步,直接传入实例作为参数
        object instance = Activator.CreateInstance(targetType);

        // 查找目标属性,优先读缓存
        string propCacheKey = $"{className}.{propertyName}";
        if (!_propertyCache.TryGetValue(propCacheKey, out PropertyInfo targetProp))
        {
            targetProp = targetType.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
            if (targetProp == null || !targetProp.CanWrite)
                throw new ArgumentException($"类{className}中不存在可写属性:{propertyName}");
            
            _propertyCache.TryAdd(propCacheKey, targetProp);
        }

        // 执行赋值,若属性为非字符串类型可在此处增加通用类型转换逻辑
        targetProp.SetValue(instance, value);
        return instance;
    }

    // 保留原有的字段读取工具方法
    public static string TryGetString(string[] transLine, int position)
    {
        return position > transLine.Length - 1 ? string.Empty : transLine[position];
    }
}

业务场景调用方式

对接分隔符文件读取、数据库配置加载的逻辑时,无需写任何case或switch判断,直接读取配置调用通用方法即可:

// 以下四个值均从数据库配置中读取
string targetEntityName = "TransLevel2";
string targetFieldName = "CD_FIELD_1";
string lineIdentifier = "SAC";
int fieldPosition = 1;

// 逐行读取分隔符文件
foreach (string[] transLine in GetFileLines())
{
    string currentLineFlag = GetLineFlag(transLine); // 按业务逻辑获取当前行标识
    if (currentLineFlag != lineIdentifier)
        continue;

    // 读取指定位置的字段值
    string fieldValue = EntityMapper.TryGetString(transLine, fieldPosition);
    // 动态完成对象创建与赋值,等价于手写 TransLevel2.CD_FIELD_1 = fieldValue
    object entity = EntityMapper.AssignProperty(targetEntityName, targetFieldName, fieldValue);

    // 如需强类型处理,可按类型转换后使用
    if (entity is TransLevel2 level2Entity)
    {
        // 执行TransLevel2对应的后续业务逻辑
    }
}

方案优势

  • 无硬编码分支:后续新增实体类型、新增字段映射规则,仅需在数据库中新增配置项,无需修改业务代码、无需重新编译发布
  • 性能损耗极低:类型、属性元数据全局缓存,仅首次加载对应配置时执行反射查找,后续赋值性能与硬编码写法几乎一致
  • 扩展成本低:如果后续需要支持非字符串类型的属性(比如int、DateTime、枚举),仅需在赋值逻辑中增加一处通用类型转换代码,无需逐个分支修改

注意事项

  • 若项目中存在重名实体类,建议数据库配置中存储带命名空间的完整类名(如YourProject.Entities.TransLevel2),直接通过Type.GetType(fullClassName)获取类型,避免匹配错误
  • 若业务场景中不需要每次新建对象(比如复用已初始化的实体实例),可以去掉方法内Activator.CreateInstance的逻辑,直接将已有实例作为参数传入方法完成赋值
  • 若实体存在非string类型的属性,可在赋值前增加通用类型转换逻辑,自动将读取到的字符串值转换为属性对应类型,适配更多业务场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 05:15:31