クラスのスパンを作る
以下のコードはエラーになります。
// Cはクラスという想定
C c0 = new C();
C c1 = new C();
Span<C> span = stackalloc C[]{ c0, c1 };// エラー
SomeMethod(span);
回避法(c#12以降)
Span<C> span = [c0,c1];
検証
ChatGPTに上記のコードについて聞いたところ、内部的に配列に変換されているからコンパイルが通るといわれました。そんなわけないだろと思って、SharpLabで以下のコードのコンパイルをして、アセンブリをChatGPTに読んでもらいました。
結果的に、配列を使っていないのでヒープを使わないと言われました。アセンブリ読める方は読んで確かめて下さい。
テストコード(コメントの指摘によって修正)
using System;
public class C {
public int age =20;
}
public static class Test{
public static void Case0()
{
Span<C> span = [new C(),new C()];
SpanMethod(span);
}
public static void Case1()
{
Span<C> span = new C[]{new C(),new C()};
SpanMethod(span);
}
public static void SpanMethod(Span<C> span){
foreach(var c in span)Console.Write(c.age);
}
}
アセンブリ
; Core CLR 9.0.124.61010 on x64
C..ctor()
L0000: mov dword ptr [rcx+8], 0x14
L0007: ret
Test.Case0()
L0000: push rbx
L0001: sub rsp, 0x40
L0005: vxorps xmm4, xmm4, xmm4
L0009: vmovdqu [rsp+0x20], ymm4
L000f: mov rbx, 0x7fff5c69cc58
L0019: mov rcx, rbx
L001c: call 0x00007fff6ba17690
L0021: mov dword ptr [rax+8], 0x14
L0028: mov [rsp+0x30], rax
L002d: mov rcx, rbx
L0030: call 0x00007fff6ba17690
L0035: mov dword ptr [rax+8], 0x14
L003c: mov [rsp+0x38], rax
L0041: lea rcx, [rsp+0x30]
L0046: mov [rsp+0x20], rcx
L004b: mov dword ptr [rsp+0x28], 2
L0053: lea rcx, [rsp+0x20]
L0058: call 0x00007fff5c6a0150
L005d: nop
L005e: add rsp, 0x40
L0062: pop rbx
L0063: ret
Test.Case1()
L0000: push rsi
L0001: push rbx
L0002: sub rsp, 0x38
L0006: xor eax, eax
L0008: mov [rsp+0x28], rax
L000d: mov rcx, 0x7fff5c69e150
L0017: mov edx, 2
L001c: call 0x00007fff6ba17850
L0021: mov rbx, rax
L0024: mov rsi, 0x7fff5c69cc58
L002e: mov rcx, rsi
L0031: call 0x00007fff6ba17690
L0036: mov dword ptr [rax+8], 0x14
L003d: lea rcx, [rbx+0x10]
L0041: mov rdx, rax
L0044: call 0x00007fff0bd10010
L0049: mov rcx, rsi
L004c: call 0x00007fff6ba17690
L0051: mov dword ptr [rax+8], 0x14
L0058: lea rcx, [rbx+0x18]
L005c: mov rdx, rax
L005f: call 0x00007fff0bd10010
L0064: add rbx, 0x10
L0068: mov [rsp+0x28], rbx
L006d: mov dword ptr [rsp+0x30], 2
L0075: lea rcx, [rsp+0x28]
L007a: call 0x00007fff5c6a0150
L007f: nop
L0080: add rsp, 0x38
L0084: pop rbx
L0085: pop rsi
L0086: ret
Test.SpanMethod(System.Span`1<C>)
L0000: push rdi
L0001: push rsi
L0002: push rbx
L0003: sub rsp, 0x20
L0007: mov rbx, [rcx]
L000a: mov esi, [rcx+8]
L000d: test esi, esi
L000f: jle short L002e
L0011: xor edi, edi
L0013: mov rcx, [rbx+rdi]
L0017: mov ecx, [rcx+8]
L001a: mov rax, 0x29e289c48a0
L0024: call qword ptr [rax]
L0026: add rdi, 8
L002a: dec esi
L002c: jne short L0013
L002e: add rsp, 0x20
L0032: pop rbx
L0033: pop rsi
L0034: pop rdi
L0035: ret
<PrivateImplementationDetails>.InlineArrayAsSpan[[, _, , _]](...)
; Open generics cannot be JIT-compiled.
; However you can use attribute SharpLab.Runtime.JitGeneric to specify argument types.
; Example: [JitGeneric(typeof(int)), JitGeneric(typeof(string))] void M<T>() { ... }.
<PrivateImplementationDetails>.InlineArrayElementRef[[, _, , _]](...)
; Open generics cannot be JIT-compiled.
; However you can use attribute SharpLab.Runtime.JitGeneric to specify argument types.
; Example: [JitGeneric(typeof(int)), JitGeneric(typeof(string))] void M<T>() { ... }.