[C#] C # 또는 VB.NET에서 할 수없는 MSIL에서 무엇을 할 수 있습니까? [닫은]

.NET 언어로 작성된 모든 코드는 MSIL로 컴파일되지만 MSIL 만 직접 사용할 수있는 특정 작업 / 작업이 있습니까?

MSIL에서 C #, VB.NET, F #, j # 또는 기타 .NET 언어보다 쉽게 ​​수행 할 수있는 작업을 살펴 ​​보겠습니다.

지금까지 우리는 이것을 가지고 있습니다 :

  1. 꼬리 재귀
  2. 일반 공분산
  3. 반환 유형 만 다른 과부하
  4. 액세스 수정 자 무시
  5. System.Object에서 상속 할 수없는 클래스가 있습니다.
  6. 필터링 된 예외 (vb.net에서 수행 가능)
  7. 현재 정적 클래스 유형의 가상 메소드를 호출합니다.
  8. 박스형 버전의 값 유형에 대한 핸들을 가져옵니다.
  9. 시도 / 결함을 수행하십시오.
  10. 금지 된 이름 사용.
  11. 값 유형에 대한 고유 한 매개 변수없는 생성자를 정의하십시오 .
  12. raise요소를 사용하여 이벤트를 정의하십시오 .
  13. CLR에서는 허용하지만 C #에서는 허용하지 않는 일부 변환이 있습니다.
  14. main()방법을 만들지 마십시오 .entrypoint.
  15. 기본 int및 기본 unsigned int유형으로 직접 작업하십시오.
  16. 과도 포인터로 재생
  17. MethodBodyItem의 emitbyte 지시어
  18. 비 System.Exception 유형을 던지고 잡습니다.
  19. 상속 열거 형 (확인되지 ​​않음)
  20. 바이트 배열을 (4 배 더 작은) 정수 배열로 취급 할 수 있습니다.
  21. 필드 / 방법 / 속성 / 이벤트는 모두 같은 이름 (확인되지 ​​않음)을 가질 수 있습니다.
  22. 자체 catch 블록에서 try 블록으로 다시 분기 할 수 있습니다.
  23. famandassem 액세스 지정자에 액세스 할 수 있습니다 ( protected internalfam 또는 assem 임 )
  24. <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


답변

protectedinternal수정자를 결합 할 수 있습니다. C #에서 protected internal멤버 를 작성 하면 어셈블리 및 파생 클래스에서 액세스 할 수 있습니다. 비아 MSIL 당신은 어셈블리에서 파생 된 클래스에서 액세스 할 수있는 멤버 얻을 수 있습니다 . (나는 그것이 매우 유용 할 수 있다고 생각합니다!)


답변

오, 나는 당시에 이것을 발견하지 못했습니다. jon-skeet 태그를 추가하면 더 가능성이 높지만 자주 확인하지는 않습니다.

이미 좋은 답변을 얻은 것 같습니다. 게다가:

  • C #에서는 박스형 버전의 값 형식을 처리 할 수 ​​없습니다. C ++ / CLI에서 가능
  • C #에서는 시도 / 결함을 수행 할 수 없습니다 ( “결함”은 “모든 것을 잡아서 블록 끝에서 다시 던지다”또는 “마지막이지만 실패한 경우에만”과 같습니다)
  • C #에서는 금지하지만 법적 IL에는 많은 이름이 있습니다.
  • IL을 사용하면 값 형식에 대한 고유 한 매개 변수없는 생성자정의 할 수 있습니다 .
  • C #에서 “raise”요소를 사용하여 이벤트를 정의 할 수 없습니다. (VB에서는 사용자 정의 이벤트에 있지만 “기본”이벤트 하나를 포함하지 않습니다.)
  • 일부 변환은 CLR에서는 허용되지만 C #에서는 허용되지 않습니다. 당신을 통해 갈 경우 objectC #에서 이러한 작업 가끔 것이다. 예를 들어 uint [] / int [] SO 질문 을 참조하십시오 .

다른 것을 생각하면 여기에 추가하겠습니다 …


답변

CLR은 이미 일반 공 / 반공 차를 지원하지만 C #은 4.0까지이 기능을 제공하지 않습니다.


답변

IL에서는에서 파생 된 형식뿐만 아니라 모든 형식을 던지고 잡을 수 있습니다 System.Exception.