如何使用 in 参数直接调用带有 ref 参数的方法
Posted
技术标签:
【中文标题】如何使用 in 参数直接调用带有 ref 参数的方法【英文标题】:How to directly call a method with ref parameter using in parameter 【发布时间】:2019-05-07 04:44:50 【问题描述】:我正在使用旧库中的方法:F (ref T t) where T: struct
。仅出于性能原因将其声明为ref
,并且不会修改它接收到的数据。此库无法更改。
在我的代码中,我有一个新方法 G (in T t) where T: struct
调用 F
。
有没有办法直接用我收到的参考资料调用F
,而无需先将其复制到临时文件中?
【问题讨论】:
方法是让你的函数也成为一个参考函数。然后你就一直把参考递过来。 In、ref 和 out 只是它们的意图声明不同:“in 关键字导致参数通过引用传递。它就像 ref 或 out 关键字,只是 in 参数不能被被调用的方法。虽然可以修改 ref 参数,但 out 参数必须由被调用的方法修改,并且这些修改在调用上下文中是可观察的。 in 将一直是正确的工具。但如果缺少这一点,您可能也必须使用 ref 。编译器不允许您在 ref 参数点上放置 in 参数,这正是 in 存在的原因。 【参考方案1】:我刚刚读到“in”。显然,in、ref 和 out 都是引用调用的一种形式。然而,主要区别在于“他们的意图声明”。
in
参数无法修改。它们只是出于性能原因的参考,如果有的话。
ref
参数可能会或可能不会被修改。它最接近经典的“引用调用”。事实上,这是您通过裸指针实现它时获得的唯一方法
out
参数有需要修改;如果一个值需要初始化(如构造函数中的只读),这可能是相关的 - 如果它作为输出变量提交,编译器可以放心将设置。其他函数编译器确保了这一点。
在某种程度上in
是一种“参考,但只读”。无法将您收到的“输入”内容分配给“参考”或“输出”,并阻止您意外更改值。我想你也不会在那里使用 ref (这使得这可能毫无意义)或复制。
【讨论】:
对不起,这是一个通用的答案,不是很有帮助。我知道关键字的作用。我正在寻找一种规避正常操作的方法,希望通过一些巧妙的类型转换或类似的方法而不是使用 Emit 来这样做(这是我目前正在做的)。【参考方案2】:是的,有办法(但它使用了不安全的黑魔法)。
首先是免责声明。
F
方法不修改struct
的事实只是您的“约定”。对于 C# 编译器,ref
提供的 struct
是完全可变的。
拥有一个由readonly ref
通过in
提供的struct
告诉编译器:请确保这个struct
不能被变异。
顺便说一句,如果您将struct
传递为in
,您必须确保此struct
被声明为readonly struct
。否则,编译器将创建struct
的防御性副本(详情请阅读here。)这是您通常无法将readonly struct
引用传递给接受@ 的方法的第二个原因987654337@ ref
并对其进行变异。
如果您仍想解决所有这些限制,可以使用System.Runtime.CompilerServices.Unsafe
NuGet 包。
Unsafe
静态类中有一个方法可以帮助你:
public static ref T AsRef<T>(in T source);
这是一个例子:
void F<T>(ref T t) where T : struct
void G<T>(in T t) where T : struct
F(ref System.Runtime.CompilerServices.Unsafe.AsRef(in t));
【讨论】:
我会检查一下包裹,谢谢。然而,这是不正确的:“不能将只读结构引用传递给通过 ref 接受结构的方法”。你可以做到,而且不需要防御性副本,因为你实际上不能在ref T
方法中修改它,因为它是只读的。
@chase,不愉快的措辞,精致。我的意思是:如果你通过in
获得它,那么它可能是readonly
,因此将它传递给接受ref
的方法可能很危险,因为该方法可能会改变struct
。
这确实是一个非常有用的包。 AsRef
的性能似乎与直接调用相同。另外,不要再发射了,耶!
我想我的“不能真正修改它”也可以使用免责声明:不是通过传统方式。随着不安全和反思以及诸如此类的一切都消失了,正如这个包精彩地展示的那样;)以上是关于如何使用 in 参数直接调用带有 ref 参数的方法的主要内容,如果未能解决你的问题,请参考以下文章
无法通过 std::ref() 调用带有 auto& 参数的 std::invoke()
如果“错误 CS1628:无法在匿名方法、lambda 或查询表达式中使用 in ref 或 out 参数”,如何在线程中使用 ref 参数?