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

如何通过反射实现对象及子对象的实例化与更新?

反射实例化并更新包含子对象的对象的最佳实现

我需要实现一种通过反射实例化并更新包含子对象的对象的方法。当前的GetInstance函数只会创建新对象并直接覆盖原有实例,现在希望修改该函数,使其优先返回已存在的对应类型实例并更新,无实例时再创建新实例。


原GetInstance函数

public static object GetInstance(string strFullyQualifiedName)
{
    if(strFullyQualifiedName.Split(' ').Length > 1)
    {
        strFullyQualifiedName = strFullyQualifiedName.Split(' ')[0];
    }
    Type type = Type.GetType(strFullyQualifiedName);
    if (type != null)
        return Activator.CreateInstance(type);
    foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
    {
        type = asm.GetType(strFullyQualifiedName);
        if (type != null)
            return Activator.CreateInstance(type);
    }
    return null;
}

示例对象定义

public class C
{
    string C1 { get; set; }
    string C2 { get; set; }
}
public class B
{
    public string B1 { get; set; }
    public string B2 { get; set; }
    public C c { get; set; }
}
public class A
{
    public string A1 { set; get; }
    public string A2 { set; get; }
    public B b { get; set; }
}

问题复现代码

当前调用GetInstance会直接创建新的B实例覆盖原有的a.b,导致原有B1的值丢失:

static void Main(string[] args)
{
    A a = new A();
    a.b = new B();
    a.b.B1 = "B1";
    
    PropertyInfo propp = a.GetType().GetProperty("b");
    
    propp.SetValue(a, GetInstance("ConsoleApp1.B"), null);
 }

尝试的修改方案(未完成)

尝试给GetInstance增加参数传入父对象,遍历父对象的属性查找对应类型实例,但逻辑不完整:

// 省略原有查找类型的代码
if (type != null)
{
    PropertyInfo[] pLIST = o.GetType().GetProperties();
    foreach(PropertyInfo p in pLIST)
    {
        object oo = p.GetValue(o);
        if(oo != null && oo.GetType() == type)
        {
            return oo;
        }
    }
    return Activator.CreateInstance(type);
}
// 省略后续代码

// 调用方式
propp.SetValue(a, GetInstance("ConsoleApp1.B",a), null);

完整解决方案

要实现复用已有实例并更新的需求,需要调整GetInstance的逻辑:不仅要查找父对象中是否存在对应类型的实例,还要支持传入待更新的属性值,同时处理嵌套子对象的情况。以下是优化后的实现:

1. 重载GetInstance方法,支持传入父对象和待更新属性

public static object GetInstance(string strFullyQualifiedName, object parentInstance = null, Dictionary<string, object> propertyValues = null)
{
    // 处理类型名称,移除可能的额外后缀
    if(strFullyQualifiedName.Split(' ').Length > 1)
    {
        strFullyQualifiedName = strFullyQualifiedName.Split(' ')[0];
    }

    // 查找目标类型
    Type type = Type.GetType(strFullyQualifiedName);
    if (type == null)
    {
        foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
        {
            type = asm.GetType(strFullyQualifiedName);
            if (type != null)
                break;
        }
    }

    if (type == null)
        return null;

    // 优先从父对象中查找已存在的同类型实例
    object targetInstance = null;
    if (parentInstance != null)
    {
        foreach (var prop in parentInstance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
        {
            var propValue = prop.GetValue(parentInstance);
            if (propValue != null && propValue.GetType() == type)
            {
                targetInstance = propValue;
                break;
            }
        }
    }

    // 无实例则创建新实例
    if (targetInstance == null)
    {
        targetInstance = Activator.CreateInstance(type);
    }

    // 如果传入属性值,递归更新实例(包括嵌套子对象)
    if (propertyValues != null && propertyValues.Count > 0)
    {
        UpdateObjectProperties(targetInstance, propertyValues);
    }

    return targetInstance;
}

// 辅助方法:递归更新对象属性,支持嵌套子对象
private static void UpdateObjectProperties(object target, Dictionary<string, object> propertyValues)
{
    var type = target.GetType();
    foreach (var kvp in propertyValues)
    {
        var prop = type.GetProperty(kvp.Key, BindingFlags.Public | BindingFlags.Instance);
        if (prop == null)
            continue;

        // 处理嵌套子对象的更新
        if (kvp.Value is Dictionary<string, object> nestedValues && prop.PropertyType.IsClass && prop.PropertyType != typeof(string))
        {
            var nestedInstance = prop.GetValue(target) ?? Activator.CreateInstance(prop.PropertyType);
            UpdateObjectProperties(nestedInstance, nestedValues);
            prop.SetValue(target, nestedInstance);
        }
        else
        {
            prop.SetValue(target, kvp.Value);
        }
    }
}

2. 使用示例

现在可以复用已有实例并更新指定属性,不会丢失原有值:

static void Main(string[] args)
{
    A a = new A();
    a.b = new B();
    a.b.B1 = "B1"; // 原有值保留

    // 准备要更新的属性:只更新B2,保留B1
    var bProperties = new Dictionary<string, object>
    {
        { "B2", "UpdatedB2" },
        // 如需更新嵌套的C对象,可添加:
        // { "c", new Dictionary<string, object> { { "C1", "NewC1" } } }
    };

    PropertyInfo propp = a.GetType().GetProperty("b");
    // 传入父对象a和待更新属性字典,复用已有a.b实例并更新
    propp.SetValue(a, GetInstance("ConsoleApp1.B", a, bProperties), null);

    // 验证结果:原有B1保留,B2被更新
    Console.WriteLine(a.b.B1); // 输出 B1
    Console.WriteLine(a.b.B2); // 输出 UpdatedB2
}

关键改进点

  • 支持从父对象中查找已存在的同类型实例,避免创建新对象覆盖原有数据
  • 增加递归属性更新逻辑,支持嵌套子对象的更新
  • 保留原有的跨程序集类型查找逻辑,兼容不同程序集中的类型

内容的提问来源于stack exchange,提问作者Y.D

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 14:48:17