為了便於說明我重新寫了一個類似的代碼
class Program
{
static void Main(string[] args)
{
Fuck f = new Fuck();
fChange( out f);
ConsoleRead();
}
}
struct Fuck
{
public readonly int Num;
public Fuck(int value)
{
Num = value;
}
public void Change(int value out Fuck data)
{
SystemConsoleWriteLine(thisNum);
data = new Fuck(value);
SystemConsoleWriteLine(thisNum);
}
}
運行結果自然是
這是為何呢?我把Fuck的定義改成了class 即
Fuck
{
public readonly int Num;
public Fuck(int value)
{
Num = value;
}
public void Change(int value out Fuck data)
{
SystemConsoleWriteLine(thisNum);
data = new Fuck(value);
SystemConsoleWriteLine(thisNum);
}
}
運行結果是
問題肯定在於值類型與引用類型處理機制上盡管在C#中所有的類型都以object的形式存在但在內部值類型與引用類型的處理機制仍然不同
讓我們回到 readonly 的問題上來
readonly 關鍵字與 const 關鍵字不同const 字段只能在該字段的聲明中初始化readonly 字段可以在聲明或構造函數中初始化因此根據所使用的構造函數readonly 字段可能具有不同的值另外const 字段為編譯時常數而 readonly 字段可用於運行時常數
根據這段話 readonly 字段是可以在運行時更改的因此readonly 在除構造函數外的函數中肯定也可以發生改變
我們不仿來看看 readonly 字段 是怎麼改變的
進入 Change 函數之後我們可以發現變量 f 的地址並未發生改變同時this關鍵字指身的地址與傳入的參數 data 相同
執行完 data = new Fuck(value) 之後this關鍵字指向的地址data指向的地址仍然沒有改變但是該地址的值發生了變化
這麼看來問題就出在於 data = new Fuck(value) 這句話上可能有些朋友對於 out 關鍵字很疑惑其實跟 out 關鍵字並沒有太大的關系
這裡又讓我們回到了C#中對於值類型的處理上
基於值類型的變量直接包含值將一個值類型變量賦給另一個值類型變量時將復制包含的值
也就是說在給 data 賦值的時候C#將 new Fuck(value) 的值按地址復制到了data 所指向的地址中這也是為什麼把Fuck的聲明改成了class之後這個現象就並不存在了
與引用類型變量的賦值不同引用類型變量的賦值只復制對對象的引用而不復制對象本身
這麼看來要改變 readonly 的值並不需要這麼復雜的過程
輕輕修改一下代碼
unsafe static void Main(string[] args)
{
Fuck f = new Fuck();
Fuck* pf = &f;
int* p = (int*)pf;
*p = ;
fChange( out f);
ConsoleRead();
}
運行結果是
不過的確像那種奇怪的編碼方式是會引起一些奇怪的現象不知道這算不的BUG
From:http://tw.wingwit.com/Article/program/net/201311/13564.html