今天代碼用到了反射賦值,代碼是這樣寫的:
1 var objtype = obj.GetType(); 2 var Fieldinfo = objtype.GetField("I64"); 3 Fieldinfo.SetValue(obj, 100L);
當用戶傳進來的obj是class的時候無問題.但是傳進來struct的時候,即不報錯也不提示,但卻什么值都沒賦上!
經過多番查詢.直到看到這個關於struct和class的區別:
http://www.cnblogs.com/gsk99/archive/2011/05/20/1904552.html
和這個裝箱/拆箱的說明:
http://www.cnblogs.com/huashanlin/archive/2007/05/16/749359.html
其中有一段:
6:裝箱/拆箱的內部操作。
裝箱:
對值類型在堆中分配一個對象實例,並將該值復制到新的對象中。按三步進行。
第一步:新分配托管堆內存(大小為值類型實例大小加上一個方法表指針和一個SyncBlockIndex)。
第二步:將值類型的實例字段拷貝到新分配的內存中。
第三步:返回托管堆中新分配對象的地址。這個地址就是一個指向對象的引用了。
有人這樣理解:如果將Int32裝箱,返回的地址,指向的就是一個Int32。我認為也不是不能這樣理解,但這確實又有問題,一來它不全面,二來指向Int32並沒說出它的實質(在托管堆中)。
拆箱:
檢查對象實例,確保它是給定值類型的一個裝箱值。將該值從實例復制到值類型變量中。
有書上講,拆箱只是獲取引用對象中指向值類型部分的指針,而內容拷貝則是賦值語句之觸發。我覺得這並不要緊。最關鍵的是檢查對象實例的本質,拆箱和裝箱的類型必需匹配,這一點上,在IL層上,看不出原理何在,我的猜測,或許是調用了類似GetType之類的方法來取出類型進行匹配(因為需要嚴格匹配)。
我看了看我調用的:SetValue方法.第一個參數是個object,是引用類型,也就是說,當我調用的時候,其實net把我的struct復制了一份,然后在新的那份改了值,我這邊這份當然是沒有被動過的.
原因找到了,解決也就不難了,解決方案1:
在調用SetValue之前,就把我的struct轉成object,然后調用完再轉回來:
1 public struct MyStruct 2 { 3 public int TestInt; 4 } 5 6 class Program 7 { 8 static void Main(string[] args) 9 { 10 var Mystruct = new MyStruct(); 11 Type myType = typeof(MyStruct); 12 FieldInfo myFieldInfo = myType.GetField("TestInt"); 13 Object someBoxedStruct = Mystruct; 14 myFieldInfo.SetValue(someBoxedStruct, 1); 15 MyStruct someUnBoxedStruct = (MyStruct)someBoxedStruct; 16 } 17 }
嘗試了一下,是可以的.
還有一種方法,偶然搜索到的,把寫入那部分改成這樣:
1 FieldInfo fi = typeof(T).GetField(name, BindingFlags.Public | BindingFlags.Instance); 2 TypedReference reference = __makeref(obj); 3 fi.SetValueDirect(reference, x);
也是可以的.