为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
湖上湖 2022-06-12 16:44:20
我想通过指定点分隔路径来更新任何公共属性中的值。但是每当我调用我的方法时,我都会收到一条错误消息: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<>));}
查看完整描述

2 回答

?
慕盖茨4494581

TA贡献1850条经验 获得超11个赞

我认为您的原始版本最终会将值设置为“太深一层”。


我认为递归模式更容易遵循,并且需要更少的代码。这是我整理的一个快速版本,适用于简单的测试用例。


有几个优化机会(在递归调用中重建字符串)和边缘情况(如null检查),我现在没有时间处理,但我认为它们不会太难添加。


public void SetProperty(object target, string property, object setTo)

{

    var parts = property.Split('.');

    var prop = target.GetType().GetProperty(parts[0]);

    if (parts.Length == 1)

    {

        // last property

        prop.SetValue(target, setTo, null);

    }

    else

    {

        // Not at the end, go recursive

        var value = prop.GetValue(target);

        SetProperty(value, string.Join(".", parts.Skip(1)), setTo);

    }

}

这是一个 LINQPad 演示,展示了它的实际效果:


void Main()

{

    var value = new A();

    Debug.WriteLine("Original value:");

    value.Dump();


    Debug.WriteLine("Changed value:");

    SetProperty(value, "B.C.D","changed!");

    value.Dump();

}


public void SetProperty(object target, string property, object setTo)

{...}


public class A

{

    public B B { get; set; } = new B();

}


public class B

{

    public C C { get; set; } = new C();

}


public class C

{

    public string D { get; set; } = "test";

}

它产生以下结果:

//img1.sycdn.imooc.com//62a5a786000199e601660386.jpg

查看完整回答
反对 回复 2022-06-12
?
手掌心

TA贡献1942条经验 获得超3个赞

我想完成答案Bradley Uffner


public void SetProperty (object target, string property, object setTo)

{

  var parts = property.Split ('.');

  // if target object is List and target object no end target - 

  // we need cast to IList and get value by index

  if (target.GetType ().Namespace == "System.Collections.Generic"

      && parts.Length != 1)

    {

      var targetList = (IList) target;

      var value = targetList[int.Parse (parts.First ())];

      SetProperty (value, string.Join (".", parts.Skip (1)), setTo);

    }

  else

    {

      var prop = target.GetType ().GetProperty (parts[0]);

      if (parts.Length == 1)

    {

      // last property

      prop.SetValue (target, setTo, null);

    }

      else

    {

      // Not at the end, go recursive

      var value = prop.GetValue (target);

      SetProperty (value, string.Join (".", parts.Skip (1)), setTo);

    }

    }

}


查看完整回答
反对 回复 2022-06-12
  • 2 回答
  • 0 关注
  • 121 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信