为了便于说明我重新写了一个类似的代码
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