PropertyInfo.SetValue() not working but no errors
Solution 1
So I took your method and made a unit test of it:
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; }
}
This passes. Can you make it not pass in the way that you are seeing?
EDIT: With your struct, it is only marginally more complicated. See Jon Skeet's answer here regarding what's going on. As for the working code:
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; }
}
Solution 2
PropertyInfo.SetValue/GetValue worked with struct with accurate using
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
Correct way to change struct:
- box struct
- change property of boxed struct
- assign boxed struct to source
Solution 3
Found the answer. Apparently, PropertyInfo.SetValue() and PropertyInfo.GetValue() do not work for structures, only classes.
MyCustomType was unfortunately a struct, so changing this to a class made it work.
The 3rd reply in this thread states why structures do not work and classes do.
EDIT: It does work with structs, see the marked answer.
James Hay
Updated on June 11, 2022Comments
-
James Hay almost 2 years
I'm writing my own method to convert an object graph to a custom object since the JavaScriptSerializer fires errors on null values.
So this is what I have so far:
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; }
Now the
pi.SetValue()
method runs, and doesn't fire an error but when I look at the properties ofgeneric
, it's still the same as it was before hand.The first property it goes through is a boolean so the values end up like this
generic = an object of type MyCustomType generic.property = false outObj = true pi = boolean property outType = boolean
Then after the
SetValue
method runs,generic.property
is still set to false.