英文:
Use "readonly record struct" type as the out parameter of method, will it cause boxing?
问题
考虑以下代码,我在一些性能关键的地方使用它来解析数据流。在这种情况下,`message` 会被装箱吗?
```cs
readonly record struct DataMessage(ulong Number, string Str,
ReadOnlySequence<byte> Payload);
bool TryParseMessage(ref ReadOnlySequence<byte> buffer,
out DataMessage message) {
message = default;
...
message = new DataMessage(...);
return true;
}
void PerformanceCriticalFunction() {
...
while (TryParseMessage(..., out var message)) {
// 消耗消息
...
}
...
}
<details>
<summary>英文:</summary>
Consider the following code, I use this to parse data streams in some performance-critical places. In this case, will the `message` be boxed?
```cs
readonly record struct DataMessage(ulong Number, string Str,
ReadOnlySequence<byte> Payload);
bool TryParseMessage(ref ReadOnlySequence<byte> buffer,
out DataMessage message) {
message = default;
...
message = new DataMessage(...);
return true;
}
void PerformanceCriticalFunction() {
...
while (TryParseMessage(..., out var message)) {
// consume the message
...
}
...
}
答案1
得分: 3
没有。这里没有与拳击相关的内容。拳击是由以下任一情况引起的:
- 直接将值类型转换为
object
(或dynamic
,它只是一个带有口音的object
,或ValueType
- 这听起来有点讽刺) - 将值类型转换为它实现的接口(在“受限调用”之外,这很复杂,但主要涉及到
<T> where T : ISomeInterface
) - 调用未被重写的值类型上的
virtual
方法(这也与“受限调用”规则相关,如果类型位于不同的程序集中) - 使用结构作为委托的目标
- (可能还有一些其他我忘记的小众情况)
这些情况都不适用,所以...没有拳击。
如果有疑虑:测试它 - 没有发出box
指令。如果我们故意添加一个GC.KeepAlive(message)
(在我的情况下是在TryParseMessage
中)以查找预期的拳击,我们会看到类似于:
IL_0023: ldarg.2
IL_0024: ldobj DataMessage
IL_0029: box DataMessage
IL_002e: call void [System.Runtime]System.GC::KeepAlive(object)
这告诉您您要寻找的内容。
英文:
No. There is nothing here that relates to boxing. Boxing is caused by any of the following:
- converting a value-type to
object
directly (ordynamic
, which is justobject
with an accent, orValueType
- which sounds ironic) - converting a value-type to an interface that it implements (outside of "constrained call", which is ... complex to explain but mostly comes down to
<T> where T : ISomeInterface
) - calling a
virtual
method that is not overridden on a value-type (this also relates to "constrained call" rules if the type is in a different assembly) - using the struct as the target of a delegate
- (probably some other niche things I'm forgetting)
None of these things apply, so... no boxing
If in doubt: test it - there are no box
instructions emitted. If we deliberately add a GC.KeepAlive(message)
(in my case in TryParseMessage
) to look for expected boxing, we see something similar to:
IL_0023: ldarg.2
IL_0024: ldobj DataMessage
IL_0029: box DataMessage
IL_002e: call void [System.Runtime]System.GC::KeepAlive(object)
which tells you what you're looking for
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论