PropertyInfo.SetValue()无效但没有错误

Jam*_*Hay 5 c# generics reflection

我正在编写自己的方法将对象图转换为自定义对象,因为JavaScriptSerializer会在空值上触发错误.

所以这就是我到目前为止所做的:

internal static T ParseObjectGraph<T>(Dictionary<string, object> oGraph)
{
    T generic = (T)Activator.CreateInstance<T>();
    Type resType = typeof(T);
    foreach (PropertyInfo pi in resType.GetProperties())
    {
        object outObj = new object();
        if (oGraph.TryGetValue(pi.Name.ToLower(), out outObj))
        {
            Type outType = outObj.GetType();
            if (outType == pi.PropertyType)
            {                        
                pi.SetValue(generic, outObj, null);
            }
        }
    }
    return generic;
}
Run Code Online (Sandbox Code Playgroud)

现在该pi.SetValue()方法运行,并且不会触发错误,但是当我查看属性时generic,它仍然与之前的相同.

它经历的第一个属性是布尔值,因此值最终会像这样

generic = an object of type MyCustomType
generic.property = false
outObj = true
pi = boolean property
outType = boolean
Run Code Online (Sandbox Code Playgroud)

然后在SetValue方法运行后,generic.property仍然设置为false.

Ser*_*-Tm 7

PropertyInfo.SetValue/GetValue使用struct进行精确使用

struct Z
{
  public int X { get; set; }
}

  Z z1 = new Z();
  z1.GetType().GetProperty("X").SetValue(z1, 100, null);
  Console.WriteLine(z1.X); //z1.X dont changed

  object z2 = new Z();
  z2.GetType().GetProperty("X").SetValue(z2, 100, null);
  Console.WriteLine(((Z)z2).X); //z2.x changed to 100

  Z z3 = new Z();
  object _z3 = z3;
  _z3.GetType().GetProperty("X").SetValue(_z3, 100, null);
  z3 = (Z)_z3;
  Console.WriteLine(z3.X); //z3.x changed to 100
Run Code Online (Sandbox Code Playgroud)

更正结构的正确方法:

  • 盒子结构
  • 更改盒装结构的属性
  • 将盒装结构分配给源


Chr*_*ain 6

所以我采用了你的方法并对其进行了单元测试:

class PropertySetTest
{
    static readonly Type resType = typeof(Car);
    internal static T ParseObjectGraph<T>(Dictionary<string, object> oGraph)
    {
        T generic = (T)Activator.CreateInstance<T>();
        foreach (PropertyInfo pi in resType.GetProperties())
        {
            //No need to new() this
            object outObj; // = new object();
            if (oGraph.TryGetValue(pi.Name.ToLower(), out outObj))
            {
                Type outType = outObj.GetType();
                if (outType == pi.PropertyType)
                {
                    pi.SetValue(generic, outObj, null);
                }
            }
        }
        return generic;
    }

    [Test]
    public void Test()
    {
        var typeData = new Dictionary<String, Object> {{"color", "Blue"}};
        var myCar = ParseObjectGraph<Car>(typeData);
        Assert.AreEqual("Blue", myCar.Color);
    }
}

internal class Car
{
    public String Color { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这过去了.你能否以你所看到的方式传递它?

编辑:使用您的结构,它只是稍微复杂一点.见乔恩斯基特的答案在这里就发生了什么事情.至于工作代码:

class PropertySetTest
{
    static readonly Type resType = typeof(Car);
    internal static T ParseObjectGraph<T>(Dictionary<string, object> oGraph)
    {
        Object generic = Activator.CreateInstance<T>();
        foreach (var pi in resType.GetProperties())
        {
            //No need to new() this
            object outObj; // = new object();
            if (oGraph.TryGetValue(pi.Name.ToLower(), out outObj))
            {
                var outType = outObj.GetType();
                if (outType == pi.PropertyType)
                    pi.SetValue(generic, outObj, null);
            }
        }
        return (T)generic;
    }

    [Test]
    public void Test()
    {
        var typeData = new Dictionary<String, Object> {{"color", "Blue"}};
        var myCar = ParseObjectGraph<Car>(typeData);
        Assert.AreEqual("Blue", myCar.Color);
    }
}

internal struct Car
{
    public String Color { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

  • 请参阅我的更新,了解如何使其适用于结构. (2认同)
  • 诀窍是当你使用带有struct(它是一个值类型)的泛型方法时,语义会发生变化.将值类型(您的`generic`变量)转换为`Object`(称为装箱)在托管堆上创建该值类型的*新副本*.因此,在您的原始示例中,您键入值类型(制作副本)*然后在副本*上设置属性,然后返回原始(未初始化)的属性.我改变的只是把它投到`T`的地方. (2认同)

Jam*_*Hay 5

找到了答案.显然,PropertyInfo.SetValue()和PropertyInfo.GetValue()不适用于结构,只适用于类.

遗憾的是,MyCustomType是一个结构体,因此将其更改为类使其工作.

这个帖子中的第三个回复说明了为什么结构不起作用而类没有.

编辑:它确实适用于结构,请参阅标记的答案.

  • 结构确实有效 - 您只需要确保拆箱结构并返回该结构,而不是返回原始的预先装箱值。请参阅我的答案以了解如何执行此操作。 (2认同)