.NET 언어로 작성된 모든 코드는 MSIL로 컴파일되지만 MSIL 만 직접 사용할 수있는 특정 작업 / 작업이 있습니까?
MSIL에서 C #, VB.NET, F #, j # 또는 기타 .NET 언어보다 쉽게 수행 할 수있는 작업을 살펴 보겠습니다.
지금까지 우리는 이것을 가지고 있습니다 :
- 꼬리 재귀
- 일반 공분산
- 반환 유형 만 다른 과부하
- 액세스 수정 자 무시
- System.Object에서 상속 할 수없는 클래스가 있습니다.
- 필터링 된 예외 (vb.net에서 수행 가능)
- 현재 정적 클래스 유형의 가상 메소드를 호출합니다.
- 박스형 버전의 값 유형에 대한 핸들을 가져옵니다.
- 시도 / 결함을 수행하십시오.
- 금지 된 이름 사용.
- 값 유형에 대한 고유 한 매개 변수없는 생성자를 정의하십시오 .
raise
요소를 사용하여 이벤트를 정의하십시오 .- CLR에서는 허용하지만 C #에서는 허용하지 않는 일부 변환이 있습니다.
- 로
main()
방법을 만들지 마십시오.entrypoint
. - 기본
int
및 기본unsigned int
유형으로 직접 작업하십시오. - 과도 포인터로 재생
- MethodBodyItem의 emitbyte 지시어
- 비 System.Exception 유형을 던지고 잡습니다.
- 상속 열거 형 (확인되지 않음)
- 바이트 배열을 (4 배 더 작은) 정수 배열로 취급 할 수 있습니다.
- 필드 / 방법 / 속성 / 이벤트는 모두 같은 이름 (확인되지 않음)을 가질 수 있습니다.
- 자체 catch 블록에서 try 블록으로 다시 분기 할 수 있습니다.
- famandassem 액세스 지정자에 액세스 할 수 있습니다 (
protected internal
fam 또는 assem 임 ) <Module>
전역 함수 또는 모듈 이니셜 라이저를 정의 하기 위해 클래스에 직접 액세스합니다 .
답변
MSIL은 다음과 같은 이유로 인해 반환 유형 만 다른 과부하를 허용합니다.
call void [mscorlib]System.Console::Write(string)
또는
callvirt int32 ...
답변
C # 및 VB를 포함한 대부분의 .Net 언어는 MSIL 코드의 꼬리 재귀 기능을 사용하지 않습니다.
테일 재귀는 기능적 언어에서 일반적인 최적화입니다. 메소드 B가 호출되면 메소드 A의 스택이 할당 해제 될 수 있도록 메소드 B의 값을 리턴하여 메소드 A가 종료 될 때 발생합니다.
MSIL 코드는 꼬리 재귀를 명시 적으로 지원하며 일부 알고리즘의 경우 중요한 최적화가 될 수 있습니다. 그러나 C # 및 VB는이를 수행하기위한 지시 사항을 생성하지 않으므로 수동으로 (또는 F # 또는 다른 언어를 사용하여) 수행해야합니다.
C #에서 tail-recursion을 수동으로 구현하는 방법의 예는 다음과 같습니다.
private static int RecursiveMethod(int myParameter)
{
// Body of recursive method
if (BaseCase(details))
return result;
// ...
return RecursiveMethod(modifiedParameter);
}
// Is transformed into:
private static int RecursiveMethod(int myParameter)
{
while (true)
{
// Body of recursive method
if (BaseCase(details))
return result;
// ...
myParameter = modifiedParameter;
}
}
하드웨어 스택에서 힙 할당 스택 데이터 구조로 로컬 데이터를 이동하여 재귀를 제거하는 것이 일반적입니다. 위와 같이 tail-call 재귀 제거에서 스택이 완전히 제거됩니다. 이는 상당히 좋은 최적화입니다. 또한 반환 값은 긴 콜 체인을 걸을 필요는 없지만 직접 반환됩니다.
그러나 CIL은이 기능을 언어의 일부로 제공하지만 C # 또는 VB에서는 수동으로 구현해야합니다. (지터는 또한이 최적화를 자체적으로 자유롭게 만들 수 있지만, 그것은 완전히 다른 문제입니다.)
답변
MSIL에는 System.Object에서 상속 할 수없는 클래스가있을 수 있습니다.
샘플 코드 : ilasm.exe로 컴파일 업데이트 : “/ NOAUTOINHERIT”를 사용하여 어셈블러가 자동 상속되지 않도록해야합니다.
// Metadata version: v2.0.50215
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 2:0:0:0
}
.assembly sample
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module sample.exe
// MVID: {A224F460-A049-4A03-9E71-80A36DBBBCD3}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x02F20000
// =============== CLASS MEMBERS DECLARATION ===================
.class public auto ansi beforefieldinit Hello
{
.method public hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "Hello World!"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Hello::Main
} // end of class Hello
답변
protected
및 internal
수정자를 결합 할 수 있습니다. C #에서 protected internal
멤버 를 작성 하면 어셈블리 및 파생 클래스에서 액세스 할 수 있습니다. 비아 MSIL 당신은 어셈블리에서 파생 된 클래스에서 액세스 할 수있는 멤버 얻을 수 있습니다 만 . (나는 그것이 매우 유용 할 수 있다고 생각합니다!)
답변
오, 나는 당시에 이것을 발견하지 못했습니다. jon-skeet 태그를 추가하면 더 가능성이 높지만 자주 확인하지는 않습니다.
이미 좋은 답변을 얻은 것 같습니다. 게다가:
- C #에서는 박스형 버전의 값 형식을 처리 할 수 없습니다. C ++ / CLI에서 가능
- C #에서는 시도 / 결함을 수행 할 수 없습니다 ( “결함”은 “모든 것을 잡아서 블록 끝에서 다시 던지다”또는 “마지막이지만 실패한 경우에만”과 같습니다)
- C #에서는 금지하지만 법적 IL에는 많은 이름이 있습니다.
- IL을 사용하면 값 형식에 대한 고유 한 매개 변수없는 생성자 를 정의 할 수 있습니다 .
- C #에서 “raise”요소를 사용하여 이벤트를 정의 할 수 없습니다. (VB에서는 이 사용자 정의 이벤트에 있지만 “기본”이벤트 하나를 포함하지 않습니다.)
- 일부 변환은 CLR에서는 허용되지만 C #에서는 허용되지 않습니다. 당신을 통해 갈 경우
object
C #에서 이러한 작업 가끔 것이다. 예를 들어 uint [] / int [] SO 질문 을 참조하십시오 .
다른 것을 생각하면 여기에 추가하겠습니다 …
답변
CLR은 이미 일반 공 / 반공 차를 지원하지만 C #은 4.0까지이 기능을 제공하지 않습니다.
답변
IL에서는에서 파생 된 형식뿐만 아니라 모든 형식을 던지고 잡을 수 있습니다 System.Exception
.