因此,我希望能够模仿C#中VB的“具有”功能,并通过StackOverflow遇到了一个相当聪明的解决方案:
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”装箱?
答案 0 :(得分:1)
这里的要点是,对于struct
上的方法,this
的含义不是值(即您的SomeStruct
的值),而是 reference (ref SomeStruct
,对于in SomeStruct
则有效地为readonly struct
)。
您不能将这种形式的托管指针装箱-运行时不支持这种情况。托管指针仅应位于堆栈上。实际上,当前在自定义ref SomeStruct
中甚至无法包含无法逃避堆栈的ref struct
字段。
编译器可以通过假装 作弊来做到这一点-即通过将托管指针从ref SomeStruct
解引用到{ {1}},并创建一个捕获上下文,其中SomeStruct
被解释为“我们之前取消引用的this
”,但是...然后编译器无法保证相同的行为和结果(实际上,我怀疑在SomeStruct
场景中可能会遇到这种情况,但是...不引入这种微妙的区别可能会更容易。
相反,编译器建议您有效地手动执行上述步骤;由于编译器不再使用readonly struct
进行处理,因此它不再必须假装尊重处理this
的通常结果,而只需要保证显式引用的复制值。这就是为什么建议(至少在当前的编译器版本上)的原因:
考虑将“ this”复制到匿名方法,lambda表达式或查询表达式之外的局部变量中,并改用局部变量。
因此,大多数lambda,局部方法等可以通过以下实用的步骤来实现:
this
然后在您的lambda /本地方法等中:触摸MyStruct copy = this; // dereference
,而不是触摸Something
或this.Something
。现在,捕获上下文中仅包含copy.Something
,并且copy
不受copy
规则的约束(因为:它不是ref SomeStruct
-它是ref SomeStruct
)。
确实,但是,这意味着,如果您的意图是变异SomeStruct
(并将该可见的就地 ,而不是作为返回值),那么它将无法正常工作。您只需要变异副本(即this
)。如果确实存在,这正是编译器必须执行的操作,但至少现在,复制步骤(取消引用)在您的代码中是显式且可见的。