今天看到了一个很easy的帖子,如下:自定义一个类,然后定义一个与这个类结构一样的结构体,如何将这个类的实例的各种属性赋给与该类结构相同的结构体的对象.(不想用逐个属性赋值的方法)。 一看之下,反射不是轻松搞定吗。后来自己做了个测试,发现对于值类型来说,好像有点小问题。代码如下: struct test1 { private int i; public int I { get{return this.i;} set{this.i = value;} } private int j; float k; } class class2 { private int i; public int I { get{return this.i;} set{this.i = value;} } private int j; float k; } 上面定义了一个结构,一个类。下面开始进行反射。 static void Main(string[] args) { class2 c1 = new class2(); c1.I = 10; test1 t1 = new test1(); ArrayList al = new ArrayList(); al.Add(t1); foreach(PropertyInfo info in c1.GetType().GetProperties()) { PropertyInfo tinfo = al[0].GetType().GetProperty(info.Name); tinfo.SetValue(al[0],info.GetValue(c1,null),null); tinfo = t1.GetType().GetProperty(info.Name); tinfo.SetValue(t1,info.GetValue(c1,null),null); } Console.WriteLine(t1.I); Console.WriteLine(((test1)al[0]).I); Console.ReadLine(); } 最后的结果输入如下:0,10。 莫非Reflection不适用于ValueType?装箱之后,结果是正确的......,但是之前,就不行。 为什么装箱之后就会OK,装箱之前就不行呢。遵循这个思路,终于看到SetValue这个方法的参数列表是这个样子.SetValue(object obj ,object value......);问题就出在这个地方。 这样一来,SetValue得到t1的时候,首先将其装箱,然后给其设值,然后这个装箱后的t1就木有了。。。。(tinfo.SetValue(t1,info.GetValue(c1,null),null); 所以外面的结果0,是正确的。 如果先将t1装箱,al.Add(t1)。再调用SetValue的时候,直接传递进去的就是一个object,所以SetValue不需要进行内部装箱,而t1的装箱之后的引用还在。(tinfo.SetValue(al[0],info.GetValue(c1,null),null);)所以,结果是10,也是正确的。 所以,当把值类型的实例当成Object传递的时候,要注意这个潜在的装箱问题。 主要是开始的时候思路受到了Reflection的影响,如果单独考虑下面的问题,估计很轻松就会找到答案。 struct s1; private void change(object obj) { } 将s1传递进入change,在change之内进行s1某字段的修改,然后输出s1的该字段,会发现同样的结果。

评论