C# 反射 - 通过属性路径设置值

我想通过指定点分隔路径来更新任何公共属性中的值。


但是每当我调用我的方法时,我都会收到一条错误消息:


pi.SetValue(instance, value1, null);

错误信息:


对象与目标类型不匹配。


我的方法:


private void SetPathValue(object instance, string path, object value)

{

    string[] pp = path.Split('.');

    Type t = instance.GetType();

    for (int i = 0; i < pp.Length; i++)

    {

        PropertyInfo pi = t.GetProperty(pp[i]);

        if (pi == null)

        {

            throw new ArgumentException("Properties path is not correct");

        }

        else

        {

            instance = pi.GetValue(instance, null);

            t = pi.PropertyType;

            if (i == pp.Length - 1)//last

            {

               // Type targetType = IsNullableType(pi.PropertyType) ? Nullable.GetUnderlyingType(pi.PropertyType) : pi.PropertyType;

                var value1 = Convert.ChangeType(value, instance.GetType());

                pi.SetValue(instance, value1, null);//ERROR

            }

        }

    }

}


private static bool IsNullableType(Type type)

{

    return type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>));

}


湖上湖
浏览 122回答 2
2回答

慕盖茨4494581

我认为您的原始版本最终会将值设置为“太深一层”。我认为递归模式更容易遵循,并且需要更少的代码。这是我整理的一个快速版本,适用于简单的测试用例。有几个优化机会(在递归调用中重建字符串)和边缘情况(如null检查),我现在没有时间处理,但我认为它们不会太难添加。public void SetProperty(object target, string property, object setTo){&nbsp; &nbsp; var parts = property.Split('.');&nbsp; &nbsp; var prop = target.GetType().GetProperty(parts[0]);&nbsp; &nbsp; if (parts.Length == 1)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // last property&nbsp; &nbsp; &nbsp; &nbsp; prop.SetValue(target, setTo, null);&nbsp; &nbsp; }&nbsp; &nbsp; else&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // Not at the end, go recursive&nbsp; &nbsp; &nbsp; &nbsp; var value = prop.GetValue(target);&nbsp; &nbsp; &nbsp; &nbsp; SetProperty(value, string.Join(".", parts.Skip(1)), setTo);&nbsp; &nbsp; }}这是一个 LINQPad 演示,展示了它的实际效果:void Main(){&nbsp; &nbsp; var value = new A();&nbsp; &nbsp; Debug.WriteLine("Original value:");&nbsp; &nbsp; value.Dump();&nbsp; &nbsp; Debug.WriteLine("Changed value:");&nbsp; &nbsp; SetProperty(value, "B.C.D","changed!");&nbsp; &nbsp; value.Dump();}public void SetProperty(object target, string property, object setTo){...}public class A{&nbsp; &nbsp; public B B { get; set; } = new B();}public class B{&nbsp; &nbsp; public C C { get; set; } = new C();}public class C{&nbsp; &nbsp; public string D { get; set; } = "test";}它产生以下结果:

手掌心

我想完成答案Bradley Uffnerpublic void SetProperty (object target, string property, object setTo){&nbsp; var parts = property.Split ('.');&nbsp; // if target object is List and target object no end target -&nbsp;&nbsp; // we need cast to IList and get value by index&nbsp; if (target.GetType ().Namespace == "System.Collections.Generic"&nbsp; &nbsp; &nbsp; && parts.Length != 1)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; var targetList = (IList) target;&nbsp; &nbsp; &nbsp; var value = targetList[int.Parse (parts.First ())];&nbsp; &nbsp; &nbsp; SetProperty (value, string.Join (".", parts.Skip (1)), setTo);&nbsp; &nbsp; }&nbsp; else&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; var prop = target.GetType ().GetProperty (parts[0]);&nbsp; &nbsp; &nbsp; if (parts.Length == 1)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; // last property&nbsp; &nbsp; &nbsp; prop.SetValue (target, setTo, null);&nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; else&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; // Not at the end, go recursive&nbsp; &nbsp; &nbsp; var value = prop.GetValue (target);&nbsp; &nbsp; &nbsp; SetProperty (value, string.Join (".", parts.Skip (1)), setTo);&nbsp; &nbsp; }&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP