値型のメソッドを呼び出すと、.NETでボクシングが発生しますか?
-
22-07-2019 - |
質問
Stack Overflowの質問に参加していました .NETのすべてはオブジェクト? 。
1つのポスター(受け入れられた回答のコメント)では、値型でメソッド呼び出しを実行するとボクシングが発生したと考えているようです。彼は私に ボクシングとアンボクシング(C#プログラミング)ガイド) では、説明しているユースケースを正確に指定していません。
私は単一のソースを信頼する人ではないので、質問についてさらにフィードバックをもらいたいだけです。私の直感ではボクシングはありませんが、私の直感はダメです。 :D
さらに詳しく説明する:
使用した例は次のとおりです。
int x = 5;
string s = x.ToString(); // Boxing??
ここで受け入れられる答えが示すように、問題の構造体がオブジェクトから継承されたメソッドをオーバーライドする場合、ボクシングは発生しません。
ただし、構造体がメソッドをオーバーライドしない場合、" constrain" CIL コマンドはcallvirtの前に実行されます。ドキュメントによると、 OpCodes。制約フィールド 、これによりボクシングが発生します:
thisTypeが値タイプであり、 thisTypeはメソッドを実装しません 次に、ptrが逆参照され、ボックス化され、 への「this」ポインタとして渡されます callvirtメソッド命令。
解決
コードのILは次のとおりです。
L_0001: ldc.i4.5 // get a 5 on the stack
L_0002: stloc.0 // store into x
L_0003: ldloca.s x // get the address of x on the stack
L_0005: call instance string [mscorlib]System.Int32::ToString() // ToString
L_000a: stloc.1 // store in s
したがって、この場合の答えはノーです。
他のヒント
台座が指摘したように、答えがノーである場合。
ただし、インターフェイスポインターを介してメソッドを呼び出す場合はそうなります。
コードを検討してください:
interface IZot
{
int F();
}
struct Zot : IZot
{
public int F()
{
return 123;
}
}
その後
Zot z = new Zot();
z.F();
ボクシングをしません:
.locals init (
[0] valuetype ConsoleApplication1.Zot z)
L_0000: nop
L_0001: ldloca.s z
L_0003: initobj ConsoleApplication1.Zot
L_0009: ldloca.s z
L_000b: call instance int32 ConsoleApplication1.Zot::F()
L_0010: pop
L_0011: ret
しかし、これは:
IZot z = new Zot();
z.F();
.locals init (
[0] class ConsoleApplication1.IZot z,
[1] valuetype ConsoleApplication1.Zot CS<*><*>)
L_0000: nop
L_0001: ldloca.s CS<*><*>
L_0003: initobj ConsoleApplication1.Zot
L_0009: ldloc.1
L_000a: box ConsoleApplication1.Zot
L_000f: stloc.0
L_0010: ldloc.0
L_0011: callvirt instance int32 ConsoleApplication1.IZot::F()
L_0016: pop
@ ggf31316
&quot; ToStringを呼び出して、 等しいおよびGethashcodeの結果 構造がそうでなければボクシング メソッドをオーバーライドします。&quot;
ToStringを確認しました。 Int32はToStringをオーバーライドするため、そうではない構造体を作成しました。 .NET Reflector を使用して、構造体が何らかの方法でToString()を魔法でオーバーライドしないようにしました。 、そうではなかった。
したがって、コードは次のようになりました:
using System;
namespace ConsoleApplication29
{
class Program
{
static void Main(string[] args)
{
MyStruct ms = new MyStruct(5);
string s = ms.ToString();
Console.WriteLine(s);
}
}
struct MyStruct
{
private int m_SomeInt;
public MyStruct(int someInt)
{
m_SomeInt = someInt;
}
public int SomeInt
{
get
{
return m_SomeInt;
}
}
}
}
そして、MainメソッドのMSIL( ILDASM 経由)は次のとおりです。
IL_0000: ldloca.s ms
IL_0002: ldc.i4.5
IL_0003: call instance void ConsoleApplication29.MyStruct::.ctor(int32)
IL_0008: ldloca.s ms
IL_000a: constrained. ConsoleApplication29.MyStruct
IL_0010: callvirt instance string [mscorlib]System.Object::ToString()
IL_0015: stloc.1
IL_0016: ldloc.1
IL_0017: call void [mscorlib]System.Console::WriteLine(string)
IL_001c: ret
今、ボクシングコールは行われていませんが、制約付き+コールvirtに関するドキュメントでは、ボクシングが行われることが記載されています。おー
引用:
thisTypeが値タイプであり、 thisTypeはメソッドを実装しません 次に、ptrが逆参照され、ボックス化され、 への「this」ポインタとして渡されます callvirtメソッド命令。
構造がメソッドをオーバーライドしない場合、ToString、Equals、およびGethashcodeを呼び出すとボクシングが発生すると考えています。