最近对 C# 7 的添加非常棒,现在在最新版本中我们可以将 ValueType
(struct
) 实例传递给函数 -通过使用新的 in
关键字更有效地引用 ('by-ref')。
在方法声明中使用 in
或 ref
意味着您可以避免整个 struct
的额外“memory-blt”副本,这通常需要以保留按值语义。使用 in
,您可以获得此好处(将指针传递给源 ValueType
本身),但与 ref
不同,不允许被调用者修改该目标(由编译器强制执行)。
除了提高设计意图的严谨性之外,in
比 ref
有一个额外的好处,即调用站点语法比 ref< 更宽松
。事实上,您不需要在调用站点提及 in
关键字;这是可选的。
无论如何,我注意到您显然可以使用 in
属性参数定义 C# 运算符重载。
public static bool operator ==(in FILE_ID_INFO x, in FILE_ID_INFO y) => eq(in x, in y);
// works: -----^ -----^
如果 by-ref 语义确实在运行时行为中占主导地位,那就太好了。但我会觉得这令人惊讶,因为即使 C# 允许您在方法调用中省略 in
关键字,调用站点生成的代码确实 需要不同。也就是说,它需要发出(例如)OpCodes.Ldflda
而不是 OpCodes.Ldfld
,等等。
还有一个事实是,运算符重载没有传统的方法“调用点”可以用(尽管是可选的)in
关键字装饰:
var fid1 = default(FILE_ID_INFO);
var fid2 = default(FILE_ID_INFO);
bool q = fid1 == fid2;
// ^--- in? ---^
那么,有没有人知道编译器、JIT 和运行时是否会尊重代码似乎被允许表达的内容,以便使用 in
参数调用运算符重载实际上将获得 by-ref 语义?我在文档中找不到任何关于这种情况的提及。由于上面显示的代码基本上继续像没有 in
标记一样工作,我想替代方案是 in
关键字在这里被默默地忽略?
最佳答案
简短回答:编译器做正确的事情。相信编译器。
长答案:
重载运算符只是静态方法的语法糖。重载运算符的调用只是调用该方法的语法糖。
也就是说,
public static bool operator ==(S s1, S s2) { ... }
只是类似
的语法糖public static bool op_Equality(S s1, S s2) { ... }
和
if (s1 == s2)
只是一个语法糖
if (S.op_Equality(s1, s2))
因此,对于普通静态方法和普通静态方法调用上的 in
注释,任何行为都适用于作为运算符的静态方法,以及作为使用这些运算符的表达式的静态方法调用。
关于C#7 'in' 允许运算符重载的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48570084/