Sharplabで#ifとConditionalでデバッグログ出力を消すとどんなILになるかを確認する
はじめに
デバッグログを消すときに#ifとConditionalを使用したときに、実際どんなILが生成されているかをSharpLabを使用して確認する。
SharpLabの設定はCode:C#、Platforms/Roslyn branches:Default、Results:ILでDebugとReleaseを切り替えて確認する。
テスト
テストコードの#define DEBUG_LOGをありとコメントアウトでした状態で確認する。
あり → #define DEBUG_LOG
コメントアウト → //#define DEBUG_LOG
#define DEBUG_LOGあり
テストに使用するコード
DEBUG_LOGあり
#define DEBUG_LOG
using System;
using System.Diagnostics;
public class C {
static readonly String log3 = "Debug Log3";
const String log4 = "Debug Log4";
public void M() {
MyDebugLog("Debug Log1");
var log2 = "Debug Log2";
MyDebugLog(log2);
MyDebugLog(log3);
MyDebugLog(log4);
var ans = add(10,20);
MyDebugLog($"and = {ans}");
}
[Conditional("DEBUG_LOG")]
private void MyDebugLog(String str)
{
#if DEBUG_LOG
Console.WriteLine(str);
#endif
}
private int add(int a, int b)
{
return a+b;
}
}
IL Debug
ldstr "Debug Log1"、ldstr "Debug Log2"、ldstr "Debug Log3"、ldstr "Debug Log4"、ldstr "and = "の文字列が残る。
IL Debug
.assembly _
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = (
01 00 08 00 00 00 00 00
)
.custom instance void [System.Runtime]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = (
01 00 01 00 54 02 16 57 72 61 70 4e 6f 6e 45 78
63 65 70 74 69 6f 6e 54 68 72 6f 77 73 01
)
.custom instance void [System.Runtime]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggableAttribute/DebuggingModes) = (
01 00 07 01 00 00 00 00
)
.permissionset reqmin = (
2e 01 80 8a 53 79 73 74 65 6d 2e 53 65 63 75 72
69 74 79 2e 50 65 72 6d 69 73 73 69 6f 6e 73 2e
53 65 63 75 72 69 74 79 50 65 72 6d 69 73 73 69
6f 6e 41 74 74 72 69 62 75 74 65 2c 20 53 79 73
74 65 6d 2e 52 75 6e 74 69 6d 65 2c 20 56 65 72
73 69 6f 6e 3d 38 2e 30 2e 30 2e 30 2c 20 43 75
6c 74 75 72 65 3d 6e 65 75 74 72 61 6c 2c 20 50
75 62 6c 69 63 4b 65 79 54 6f 6b 65 6e 3d 62 30
33 66 35 66 37 66 31 31 64 35 30 61 33 61 15 01
54 02 10 53 6b 69 70 56 65 72 69 66 69 63 61 74
69 6f 6e 01
)
.hash algorithm 0x00008004 // SHA1
.ver 0:0:0:0
}
.class private auto ansi '<Module>'
{
} // end of class <Module>
.class public auto ansi beforefieldinit C
extends [System.Runtime]System.Object
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = (
01 00 01 00 00
)
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = (
01 00 00 00 00
)
// Fields
.field private static initonly string log3
.field private static literal string log4 = "Debug Log4"
// Methods
.method public hidebysig
instance void M () cil managed
{
// Method begins at RVA 0x2050
// Code size 108 (0x6c)
.maxstack 4
.locals init (
[0] string log2,
[1] int32 ans,
[2] valuetype [System.Runtime]System.Runtime.CompilerServices.DefaultInterpolatedStringHandler
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldstr "Debug Log1"
IL_0007: call instance void C::MyDebugLog(string)
IL_000c: nop
IL_000d: ldstr "Debug Log2"
IL_0012: stloc.0
IL_0013: ldarg.0
IL_0014: ldloc.0
IL_0015: call instance void C::MyDebugLog(string)
IL_001a: nop
IL_001b: ldarg.0
IL_001c: ldsfld string C::log3
IL_0021: call instance void C::MyDebugLog(string)
IL_0026: nop
IL_0027: ldarg.0
IL_0028: ldstr "Debug Log4"
IL_002d: call instance void C::MyDebugLog(string)
IL_0032: nop
IL_0033: ldarg.0
IL_0034: ldc.i4.s 10
IL_0036: ldc.i4.s 20
IL_0038: call instance int32 C::'add'(int32, int32)
IL_003d: stloc.1
IL_003e: ldarg.0
IL_003f: ldloca.s 2
IL_0041: ldc.i4.6
IL_0042: ldc.i4.1
IL_0043: call instance void [System.Runtime]System.Runtime.CompilerServices.DefaultInterpolatedStringHandler::.ctor(int32, int32)
IL_0048: ldloca.s 2
IL_004a: ldstr "and = "
IL_004f: call instance void [System.Runtime]System.Runtime.CompilerServices.DefaultInterpolatedStringHandler::AppendLiteral(string)
IL_0054: nop
IL_0055: ldloca.s 2
IL_0057: ldloc.1
IL_0058: call instance void [System.Runtime]System.Runtime.CompilerServices.DefaultInterpolatedStringHandler::AppendFormatted<int32>(!!0)
IL_005d: nop
IL_005e: ldloca.s 2
IL_0060: call instance string [System.Runtime]System.Runtime.CompilerServices.DefaultInterpolatedStringHandler::ToStringAndClear()
IL_0065: call instance void C::MyDebugLog(string)
IL_006a: nop
IL_006b: ret
} // end of method C::M
.method private hidebysig
instance void MyDebugLog (
string str
) cil managed
{
.custom instance void [System.Runtime]System.Diagnostics.ConditionalAttribute::.ctor(string) = (
01 00 09 44 45 42 55 47 5f 4c 4f 47 00 00
)
// Method begins at RVA 0x20c8
// Code size 9 (0x9)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.1
IL_0002: call void [System.Console]System.Console::WriteLine(string)
IL_0007: nop
IL_0008: ret
} // end of method C::MyDebugLog
.method private hidebysig
instance int32 'add' (
int32 a,
int32 b
) cil managed
{
// Method begins at RVA 0x20d4
// Code size 9 (0x9)
.maxstack 2
.locals init (
[0] int32
)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: add
IL_0004: stloc.0
IL_0005: br.s IL_0007
IL_0007: ldloc.0
IL_0008: ret
} // end of method C::'add'
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x20e9
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method C::.ctor
.method private hidebysig specialname rtspecialname static
void .cctor () cil managed
{
// Method begins at RVA 0x20f2
// Code size 11 (0xb)
.maxstack 8
IL_0000: ldstr "Debug Log3"
IL_0005: stsfld string C::log3
IL_000a: ret
} // end of method C::.cctor
} // end of class C
IL Release
ldstr "Debug Log1"、ldstr "Debug Log2"、ldstr "Debug Log3"、ldstr "Debug Log4"、ldstr "and = "の文字列が残る。
IL Debug
.assembly _
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = (
01 00 08 00 00 00 00 00
)
.custom instance void [System.Runtime]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = (
01 00 01 00 54 02 16 57 72 61 70 4e 6f 6e 45 78
63 65 70 74 69 6f 6e 54 68 72 6f 77 73 01
)
.custom instance void [System.Runtime]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggableAttribute/DebuggingModes) = (
01 00 02 00 00 00 00 00
)
.permissionset reqmin = (
2e 01 80 8a 53 79 73 74 65 6d 2e 53 65 63 75 72
69 74 79 2e 50 65 72 6d 69 73 73 69 6f 6e 73 2e
53 65 63 75 72 69 74 79 50 65 72 6d 69 73 73 69
6f 6e 41 74 74 72 69 62 75 74 65 2c 20 53 79 73
74 65 6d 2e 52 75 6e 74 69 6d 65 2c 20 56 65 72
73 69 6f 6e 3d 38 2e 30 2e 30 2e 30 2c 20 43 75
6c 74 75 72 65 3d 6e 65 75 74 72 61 6c 2c 20 50
75 62 6c 69 63 4b 65 79 54 6f 6b 65 6e 3d 62 30
33 66 35 66 37 66 31 31 64 35 30 61 33 61 15 01
54 02 10 53 6b 69 70 56 65 72 69 66 69 63 61 74
69 6f 6e 01
)
.hash algorithm 0x00008004 // SHA1
.ver 0:0:0:0
}
.class private auto ansi '<Module>'
{
} // end of class <Module>
.class public auto ansi beforefieldinit C
extends [System.Runtime]System.Object
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = (
01 00 01 00 00
)
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = (
01 00 00 00 00
)
// Fields
.field private static initonly string log3
.field private static literal string log4 = "Debug Log4"
// Methods
.method public hidebysig
instance void M () cil managed
{
// Method begins at RVA 0x2050
// Code size 100 (0x64)
.maxstack 4
.locals init (
[0] string log2,
[1] int32 ans,
[2] valuetype [System.Runtime]System.Runtime.CompilerServices.DefaultInterpolatedStringHandler
)
IL_0000: ldarg.0
IL_0001: ldstr "Debug Log1"
IL_0006: call instance void C::MyDebugLog(string)
IL_000b: ldstr "Debug Log2"
IL_0010: stloc.0
IL_0011: ldarg.0
IL_0012: ldloc.0
IL_0013: call instance void C::MyDebugLog(string)
IL_0018: ldarg.0
IL_0019: ldsfld string C::log3
IL_001e: call instance void C::MyDebugLog(string)
IL_0023: ldarg.0
IL_0024: ldstr "Debug Log4"
IL_0029: call instance void C::MyDebugLog(string)
IL_002e: ldarg.0
IL_002f: ldc.i4.s 10
IL_0031: ldc.i4.s 20
IL_0033: call instance int32 C::'add'(int32, int32)
IL_0038: stloc.1
IL_0039: ldarg.0
IL_003a: ldloca.s 2
IL_003c: ldc.i4.6
IL_003d: ldc.i4.1
IL_003e: call instance void [System.Runtime]System.Runtime.CompilerServices.DefaultInterpolatedStringHandler::.ctor(int32, int32)
IL_0043: ldloca.s 2
IL_0045: ldstr "and = "
IL_004a: call instance void [System.Runtime]System.Runtime.CompilerServices.DefaultInterpolatedStringHandler::AppendLiteral(string)
IL_004f: ldloca.s 2
IL_0051: ldloc.1
IL_0052: call instance void [System.Runtime]System.Runtime.CompilerServices.DefaultInterpolatedStringHandler::AppendFormatted<int32>(!!0)
IL_0057: ldloca.s 2
IL_0059: call instance string [System.Runtime]System.Runtime.CompilerServices.DefaultInterpolatedStringHandler::ToStringAndClear()
IL_005e: call instance void C::MyDebugLog(string)
IL_0063: ret
} // end of method C::M
.method private hidebysig
instance void MyDebugLog (
string str
) cil managed
{
.custom instance void [System.Runtime]System.Diagnostics.ConditionalAttribute::.ctor(string) = (
01 00 09 44 45 42 55 47 5f 4c 4f 47 00 00
)
// Method begins at RVA 0x20c0
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.1
IL_0001: call void [System.Console]System.Console::WriteLine(string)
IL_0006: ret
} // end of method C::MyDebugLog
.method private hidebysig
instance int32 'add' (
int32 a,
int32 b
) cil managed
{
// Method begins at RVA 0x20c8
// Code size 4 (0x4)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: add
IL_0003: ret
} // end of method C::'add'
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x20cd
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
IL_0006: ret
} // end of method C::.ctor
.method private hidebysig specialname rtspecialname static
void .cctor () cil managed
{
// Method begins at RVA 0x20d5
// Code size 11 (0xb)
.maxstack 8
IL_0000: ldstr "Debug Log3"
IL_0005: stsfld string C::log3
IL_000a: ret
} // end of method C::.cctor
} // end of class C
#define DEBUG_LOGコメントアウト
テストに使用するコード
DEBUG_LOGコメントアウト
//#define DEBUG_LOG
using System;
using System.Diagnostics;
public class C {
static readonly String log3 = "Debug Log3";
const String log4 = "Debug Log4";
public void M() {
MyDebugLog("Debug Log1");
var log2 = "Debug Log2";
MyDebugLog(log2);
MyDebugLog(log3);
MyDebugLog(log4);
var ans = add(10,20);
MyDebugLog($"and = {ans}");
}
[Conditional("DEBUG_LOG")]
private void MyDebugLog(String str)
{
#if DEBUG_LOG
Console.WriteLine(str);
#endif
}
private int add(int a, int b)
{
return a+b;
}
}
IL Debug
ldstr "Debug Log1"、ldstr "and = "の文字列は消える。
ldstr "Debug Log2"、ldstr "Debug Log3"、ldstr "Debug Log4"の文字列は残る。
IL Debug
.assembly _
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = (
01 00 08 00 00 00 00 00
)
.custom instance void [System.Runtime]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = (
01 00 01 00 54 02 16 57 72 61 70 4e 6f 6e 45 78
63 65 70 74 69 6f 6e 54 68 72 6f 77 73 01
)
.custom instance void [System.Runtime]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggableAttribute/DebuggingModes) = (
01 00 07 01 00 00 00 00
)
.permissionset reqmin = (
2e 01 80 8a 53 79 73 74 65 6d 2e 53 65 63 75 72
69 74 79 2e 50 65 72 6d 69 73 73 69 6f 6e 73 2e
53 65 63 75 72 69 74 79 50 65 72 6d 69 73 73 69
6f 6e 41 74 74 72 69 62 75 74 65 2c 20 53 79 73
74 65 6d 2e 52 75 6e 74 69 6d 65 2c 20 56 65 72
73 69 6f 6e 3d 38 2e 30 2e 30 2e 30 2c 20 43 75
6c 74 75 72 65 3d 6e 65 75 74 72 61 6c 2c 20 50
75 62 6c 69 63 4b 65 79 54 6f 6b 65 6e 3d 62 30
33 66 35 66 37 66 31 31 64 35 30 61 33 61 15 01
54 02 10 53 6b 69 70 56 65 72 69 66 69 63 61 74
69 6f 6e 01
)
.hash algorithm 0x00008004 // SHA1
.ver 0:0:0:0
}
.class private auto ansi '<Module>'
{
} // end of class <Module>
.class public auto ansi beforefieldinit C
extends [System.Runtime]System.Object
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = (
01 00 01 00 00
)
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = (
01 00 00 00 00
)
// Fields
.field private static initonly string log3
.field private static literal string log4 = "Debug Log4"
// Methods
.method public hidebysig
instance void M () cil managed
{
// Method begins at RVA 0x2050
// Code size 19 (0x13)
.maxstack 3
.locals init (
[0] string log2,
[1] int32 ans
)
IL_0000: nop
IL_0001: ldstr "Debug Log2"
IL_0006: stloc.0
IL_0007: ldarg.0
IL_0008: ldc.i4.s 10
IL_000a: ldc.i4.s 20
IL_000c: call instance int32 C::'add'(int32, int32)
IL_0011: stloc.1
IL_0012: ret
} // end of method C::M
.method private hidebysig
instance void MyDebugLog (
string str
) cil managed
{
.custom instance void [System.Runtime]System.Diagnostics.ConditionalAttribute::.ctor(string) = (
01 00 09 44 45 42 55 47 5f 4c 4f 47 00 00
)
// Method begins at RVA 0x206f
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method C::MyDebugLog
.method private hidebysig
instance int32 'add' (
int32 a,
int32 b
) cil managed
{
// Method begins at RVA 0x2074
// Code size 9 (0x9)
.maxstack 2
.locals init (
[0] int32
)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: add
IL_0004: stloc.0
IL_0005: br.s IL_0007
IL_0007: ldloc.0
IL_0008: ret
} // end of method C::'add'
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2089
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method C::.ctor
.method private hidebysig specialname rtspecialname static
void .cctor () cil managed
{
// Method begins at RVA 0x2092
// Code size 11 (0xb)
.maxstack 8
IL_0000: ldstr "Debug Log3"
IL_0005: stsfld string C::log3
IL_000a: ret
} // end of method C::.cctor
} // end of class C
IL Release
ldstr "Debug Log1"、ldstr "Debug Log2"[1]、ldstr "and = "の文字列は消える。
ldstr "Debug Log3"、ldstr "Debug Log4"の文字列は残る。
IL Debug
.assembly _
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = (
01 00 08 00 00 00 00 00
)
.custom instance void [System.Runtime]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = (
01 00 01 00 54 02 16 57 72 61 70 4e 6f 6e 45 78
63 65 70 74 69 6f 6e 54 68 72 6f 77 73 01
)
.custom instance void [System.Runtime]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggableAttribute/DebuggingModes) = (
01 00 02 00 00 00 00 00
)
.permissionset reqmin = (
2e 01 80 8a 53 79 73 74 65 6d 2e 53 65 63 75 72
69 74 79 2e 50 65 72 6d 69 73 73 69 6f 6e 73 2e
53 65 63 75 72 69 74 79 50 65 72 6d 69 73 73 69
6f 6e 41 74 74 72 69 62 75 74 65 2c 20 53 79 73
74 65 6d 2e 52 75 6e 74 69 6d 65 2c 20 56 65 72
73 69 6f 6e 3d 38 2e 30 2e 30 2e 30 2c 20 43 75
6c 74 75 72 65 3d 6e 65 75 74 72 61 6c 2c 20 50
75 62 6c 69 63 4b 65 79 54 6f 6b 65 6e 3d 62 30
33 66 35 66 37 66 31 31 64 35 30 61 33 61 15 01
54 02 10 53 6b 69 70 56 65 72 69 66 69 63 61 74
69 6f 6e 01
)
.hash algorithm 0x00008004 // SHA1
.ver 0:0:0:0
}
.class private auto ansi '<Module>'
{
} // end of class <Module>
.class public auto ansi beforefieldinit C
extends [System.Runtime]System.Object
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = (
01 00 01 00 00
)
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = (
01 00 00 00 00
)
// Fields
.field private static initonly string log3
.field private static literal string log4 = "Debug Log4"
// Methods
.method public hidebysig
instance void M () cil managed
{
// Method begins at RVA 0x2050
// Code size 12 (0xc)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.s 10
IL_0003: ldc.i4.s 20
IL_0005: call instance int32 C::'add'(int32, int32)
IL_000a: pop
IL_000b: ret
} // end of method C::M
.method private hidebysig
instance void MyDebugLog (
string str
) cil managed
{
.custom instance void [System.Runtime]System.Diagnostics.ConditionalAttribute::.ctor(string) = (
01 00 09 44 45 42 55 47 5f 4c 4f 47 00 00
)
// Method begins at RVA 0x205d
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method C::MyDebugLog
.method private hidebysig
instance int32 'add' (
int32 a,
int32 b
) cil managed
{
// Method begins at RVA 0x205f
// Code size 4 (0x4)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: add
IL_0003: ret
} // end of method C::'add'
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2064
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
IL_0006: ret
} // end of method C::.ctor
.method private hidebysig specialname rtspecialname static
void .cctor () cil managed
{
// Method begins at RVA 0x206c
// Code size 11 (0xb)
.maxstack 8
IL_0000: ldstr "Debug Log3"
IL_0005: stsfld string C::log3
IL_000a: ret
} // end of method C::.cctor
} // end of class C
まとめ
DEBUG_LOGコメントアウトしてReleaseビルドを行うと。
#ifとConditionalを無効にするとメソッド内で定義した文字列は消える。
static readonly、constで定義した文字列は残るためデバッグ出力用に準備して使用しない方が良い。
-
最適化により消えた? ↩︎
Discussion