값 유형에서 메소드를 호출하면 .NET에서 복싱이 발생합니까?
-
22-07-2019 - |
문제
스택 오버플로 질문에 참여하고있었습니다 .net의 모든 것이 객체입니까?.
그리고 하나의 포스터 (허용 된 답변에 대한 의견에서)는 값 유형에서 메소드 호출을 수행하면 복싱이 발생했다고 생각하는 것 같습니다. 그는 나를 지적했다 권투 및 개봉 (C# 프로그래밍 안내서) 우리가 설명하는 사용 사례를 정확하게 지정하지 않습니다.
나는 단일 소스를 신뢰하는 사람이 아니므로 질문에 대한 추가 피드백을 받고 싶었습니다. 내 직관은 권투가 없지만 직관이 빨라진다는 것입니다. :디
더 자세히 설명하기 위해 :
내가 사용한 예는 다음과 같습니다.
int x = 5;
string s = x.ToString(); // Boxing??
권투가합니다 ~ 아니다 문제의 구조물이 여기에서 허용 된 답변이 표시된대로 객체에서 상속 된 메소드를 무시하는 경우 발생합니다.
그러나 구조물이 방법을 무시하지 않으면 "제한" 실 명령은 callvirt 전에 실행됩니다. 문서에 따르면 opcodes. 제한 된 필드, 이로 인해 복싱이 발생합니다:
이 유형이 값 유형이고 thistype가 메소드를 구현하지 않으면 PTR은 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$0$0000)
L_0000: nop
L_0001: ldloca.s CS$0$0000
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
"나는 구조가 방법을 무시하지 않으면 Tostring, Equals 및 gethashcode를 호출하면 복싱이 발생한다고 생각한다."
나는 당신을 위해 Tostring을 확인했습니다. int32는 Tostring을 무시하므로 그렇지 않은 구조물을 만들었습니다. 나는 사용했다 .NET 리플렉터 구조물이 어떻게 든 마술처럼 마술처럼 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;
}
}
}
}
그리고 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
이제 권투 통화가 발생하지 않더라도 확인하면 제한된 + 통화 미덕에 대한 문서, 당신은 권투가 일어난다는 것을 알게 될 것입니다. 우
인용하다:
이 유형이 값 유형이고 thistype가 메소드를 구현하지 않으면 PTR은 CallVirt 메소드 명령어에 대한 '이'포인터로 도입되고 박스형 및 전달됩니다.
구조가 메소드를 무시하지 않으면 Tostring, Equals 및 gethashcode를 호출하면 복싱이 발생한다고 생각합니다.