为什么值类型的 "this" 不能装箱?

Why can't "this" for value types be boxed?

所以我希望能够在 C# 中模仿 VB 的 "with" 功能,并通过 Whosebug 找到了一个相当聪明的解决方案:

public static x with<x>(this x item, Func<x,x> f)
{
    item = f(item);
    return item;
}

要实现你会做这样的事情:

myObject = myObject.with(myVariable => {
    //do things
});

但是,当我尝试在具有结构字段之一的结构中实现它时,我 运行 遇到了麻烦。它说“结构内部的匿名方法[...]无法访问'this'[...]的成员。”

我对此进行了一些研究并找到了 this question 的答案,该答案最终指出 "this" 不能装箱值类型。在研究了装箱对 C# 意味着什么之后,考虑到函数的参数没有定义的类型,这是有道理的。

我的问题是,为什么 不能 "this" 对值类型进行装箱?

我想您知道在构造过程中设置属性,这很相似(并且更符合 c# 的习惯)?

class MySpecialClass
{
   public string Property1 {get;set;}
   public int Length {get;set;}
   public float Width {get;set;}
}

var p = new MySpecialClass
{
  Property1 = "PropertyValue",
  Length = 12,
  OtherThing = 1.234F
};

这里的要点是,对于 struct 上的方法,this 的含义不是 value(即你的值SomeStruct),而是 referenceref SomeStruct,或者在 readonly struct 的情况下实际上是 in SomeStruct)。

您不能将这种形式的托管指针装箱 - 这不是运行时支持的方案。托管指针只意味着在堆栈上。事实上,目前你甚至不能在自定义 ref struct 中有一个无法逃脱堆栈的 ref SomeStruct 字段。

编译器可以通过假装作弊——即通过取消引用托管从 ref SomeStructSomeStruct 的指针并创建一个捕获上下文,其中 this 被解释为 "the SomeStruct that we dereferenced earlier",但是...然后编译器不能保证相同的行为和结果(实际上,我怀疑在 readonly struct 场景中可以对此进行说明,但是......不引入这种微妙的区别可能更容易)。

相反,编译器建议您有效地执行上述步骤手动;由于编译器不再根据 this 进行处理,因此它不再需要假装尊重处理 this 的通常结果,而只需保证显式取消引用 [=] 的行为51=]copy 的值。这就是它建议的原因(至少在当前的编译器版本上):

Consider copying 'this' to a local variable outside the anonymous method, lambda expression or query expression and using the local instead.

因此,大多数 lambda、本地方法等都可以通过以下实用步骤实现:

MyStruct copy = this; // dereference

然后在您的 lambda/本地方法/等中:而不是触摸 Something 又名 this.Something - 触摸 copy.Something。现在只有 copy 包含在捕获上下文中,并且 copy 不受 ref SomeStruct 规则的约束(因为:它不是 ref SomeStruct -这是一个 SomeStruct).

确实 ,但是,这意味着如果您的意图是 变异 this(并且让 in-place,而不是 return 值),那么它将不起作用。您只会改变 copy(即 copy)。这正是编译器 无论如何 如果它撒了谎,但至少现在复制步骤(取消引用)在您的代码中是明确和可见的。