英文:
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
objectdirectly (ordynamic, which is justobjectwith 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
virtualmethod 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论