C# 反射結構體struct的一個坑


今天代碼用到了反射賦值,代碼是這樣寫的:

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);

也是可以的.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM