将一个结构体的值分配给this关键字

7
我最近在研究CancellationToken结构的内部机制时,发现了一个有些奇怪的构造方式(更准确地说,是将值分配给关键字“this”)。
其中一个构造函数的代码如下:
public CancellationToken( bool canceled )
{
    this = new CancellationToken();
    if ( canceled )
    {
        this.m_source = CancellationTokenSource.InternalGetStaticSource( canceled );
    }
}

什么是指向出现this关键字的行的含义?

请注意,对于类而言,不可能对this关键字进行赋值-会出现错误Cannot assign to '<this>' because it is read-only

2个回答

6

这是C#中一个不广为人知的功能 - 它允许结构体重写其自身的数据。

就实际应用而言,你不会找到很多使用情况。

struct MyStruct
{
    int a = 1;
    int b = 2;
    int c = 3;

    public void Mutate()
    {
        a = 10;
        b = 20;
        c = 30;
    }

    public void Reset()
    {
        a = 1;
        b = 2;
        c = 3;
    }

    public void Reset2()
    {
        this = new MyStruct();
    }

    // The two Reset methods are equivilent...
}

仔细思考后,处理值类型和引用类型时,“this”所代表的含义有根本的区别。

当你在引用类型上调用“this”时,你得到的是一个指针,它存在于堆栈中,你并没有得到对象本身。该指针隐式地反向引用堆上的对象,从而抽象了间接性。现在,如果在类中分配给this是可能的,并且你会说类似于this = new MyReferenceType(),那么你将会在当前作用域内改变指针以指向不同的堆对象——你不会改变堆中的原始对象,也不会导致任何其他引用/指针引用新的堆对象。很可能,一旦你突变的指针超出了范围,你创建的新堆对象就会被垃圾回收。

当你在值类型上调用“this”时,你得到的是实际的对象,而不是引用或指针。没有间接性,因此你可以自由地覆盖这个内存位置的原始位(这正是默认构造函数所做的)。


1

仅供猜测:

每个类都是引用类型,这意味着内存分配在堆中,并且调用者通过指针访问实际数据。例如:

Customer c1 = new Customer('CUSTID');   // "Customer" is a reference type 
Customer c2 = c1;   // "c1" and "c2" points to the same memory within the heap

每个结构体都是值类型,这意味着内存分配在堆栈中,调用者处理的是实际实例而不是对该实例的引用。例如:
Customer c1 = new Customer('CUSTID');    // "Customer" is a value type 
Customer c2 = c1;   // New memory gets allocated for "c2" within the stack

考虑您的示例:

this = new Customer();

在结构体上执行以下操作只会将其初始化为零值:
mov eax,dword ptr [ebp-3Ch] ; Save pointer to "ebp-3Ch" in EAX register
xor edx,edx                 ; Clear EDX register
mov dword ptr [eax],edx     ; Write "zero" by address containing in EAX

我不知道为什么引用类型不可能实现,但我的猜测是这将需要遍历整个对象图来完全“重置”它(这可能不是一项容易的任务)。我假设在循环引用的情况下,这将变得更加值得。

再次强调,这只是我的想法,我非常希望有人能够证明或驳斥它们(当然要附上解释)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接