为什么值类型的 "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
),而是 reference(ref SomeStruct
,或者在 readonly struct
的情况下实际上是 in SomeStruct
)。
您不能将这种形式的托管指针装箱 - 这不是运行时支持的方案。托管指针只意味着在堆栈上。事实上,目前你甚至不能在自定义 ref struct
中有一个无法逃脱堆栈的 ref SomeStruct
字段。
编译器可以通过假装来作弊——即通过取消引用托管从 ref SomeStruct
到 SomeStruct
的指针并创建一个捕获上下文,其中 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
)。这正是编译器 无论如何 如果它撒了谎,但至少现在复制步骤(取消引用)在您的代码中是明确和可见的。
所以我希望能够在 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
),而是 reference(ref SomeStruct
,或者在 readonly struct
的情况下实际上是 in SomeStruct
)。
您不能将这种形式的托管指针装箱 - 这不是运行时支持的方案。托管指针只意味着在堆栈上。事实上,目前你甚至不能在自定义 ref struct
中有一个无法逃脱堆栈的 ref SomeStruct
字段。
编译器可以通过假装来作弊——即通过取消引用托管从 ref SomeStruct
到 SomeStruct
的指针并创建一个捕获上下文,其中 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
)。这正是编译器 无论如何 如果它撒了谎,但至少现在复制步骤(取消引用)在您的代码中是明确和可见的。