Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

override 메서드가 정의된 타입의 인스턴스로 base 메서드를 호출하는 방법 - 두 번째 이야기

이번 글은 다음의 글에 대한 보강입니다. ^^

override 메서드가 정의된 타입의 인스턴스로 base 메서드를 호출하는 방법
; https://www.sysnet.pe.kr/2/0/1564

위의 글에서는 DynamicMethod를 이용해 callvirt를 call로 강제 지정하는 방법을 사용하고 있는데요. 이 기법을 .NET 1.1에서 사용하려면 어떻게 해야 할까요? ^^

아쉽게도 DynamicMethod는 .NET 2.0부터 지원되기 때문에 1.1 이하에서는 사용할 수 없습니다. (물론, 1.1 용으로 아직도 응용 프로그램을 만드는 경우는 거의 없겠지만.)

이에 대해 혹시나 또 누군가 친절하게 방법을 만들어 두지 않았을까 검색해 보았는데... 아쉽게도 이번에는 꽝이군요. ^^

C# .NET 1.1 - MethodBase.Invoke on virtual methods (dynamic method lookup)
; http://www.codeproject.com/Messages/1618442/Csharp-NET-1-1-MethodBase-Invoke-on-virtual-method.aspx

방법이 없을까...? 생각하다가 한 가지 아이디어가 떠 올랐습니다. 혹시 제가 무슨 생각을 한 것인지 상상이 가시나요? ^^

힌트를 하나 드리자면, 다음과 같이 테스트 코드를 만드는 것으로 시작할 수 있습니다.

using System;

namespace ConsoleApplication1
{
    class BaseClass
    {
        public virtual void Do()
        {
            Console.WriteLine("BaseClass.Do");
        }
    }

    class DerivedClass : BaseClass
    {
        public override void Do()
        {
            Console.WriteLine("DerivedClass.Do");

            base.Do();
        }
    }
    static class Program
    {
        static void Main(string[] args)
        {
            DerivedClass dc = new DerivedClass();
            // dc.Do();

            DirectInvoke(dc);
        }

        private static void DirectInvoke(DerivedClass dc)
        {
            dc.Do();
        }
    }
}

그러니까, 요점은 callvirt가 아닌 call을 해주면 되기 때문에 이를 IL 어셈블리를 직접 변경해서 구현할 수 있습니다. 따라서 산출된 DLL/EXE 파일에 대해 다음과 같이 IL 코드로 역어셈블을 하면,

C:\Users\bin\Debug>ildasm ConsoleApplication1.exe /OUTPUT=test.il

다음과 같은 결과물을 얻을 수 있습니다.

// Metadata version: v4.0.30319
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                        
  .ver 4:0:0:0
}

// ... 생략 ...

.class private auto ansi beforefieldinit ConsoleApplication1.DerivedClass
       extends ConsoleApplication1.BaseClass
{
// ... 생략 ...

  .method private hidebysig static void  DirectInvoke(class ConsoleApplication1.DerivedClass dc) cil managed
  {
    // Code size       9 (0x9)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldarg.0
    IL_0002:  callvirt   instance void ConsoleApplication1.BaseClass::Do()
    IL_0007:  nop
    IL_0008:  ret
  } // end of method Program::DirectInvoke

} // end of class ConsoleApplication1.Program

그럼, 위의 callvirt를 call로 간단하게 변경해 주고,

.method private hidebysig static void  DirectInvoke(class ConsoleApplication1.DerivedClass dc) cil managed
{
	// Code size       9 (0x9)
	.maxstack  8
	IL_0000:  nop
	IL_0001:  ldarg.0
	IL_0002:  call   instance void ConsoleApplication1.BaseClass::Do()
	IL_0007:  nop
	IL_0008:  ret
} // end of method Program::DirectInvoke

다시 IL 컴파일을 해주면,

C:\Users\bin\Debug>ilasm test.il

Microsoft (R) .NET Framework IL Assembler.  Version 4.0.30319.33440
Copyright (c) Microsoft Corporation.  All rights reserved.
Assembling 'test.il'  to EXE --> 'test.exe'
Source file is ANSI

Assembled method ConsoleApplication1.BaseClass::Do
Assembled method ConsoleApplication1.BaseClass::.ctor
Assembled method ConsoleApplication1.DerivedClass::Do
Assembled method ConsoleApplication1.DerivedClass::.ctor
Assembled method ConsoleApplication1.Program::Main
Assembled method ConsoleApplication1.Program::DirectInvoke
Creating PE file

Emitting classes:
Class 1:        ConsoleApplication1.BaseClass
Class 2:        ConsoleApplication1.DerivedClass
Class 3:        ConsoleApplication1.Program

Emitting fields and methods:
Global
Class 1 Methods: 2;
Class 2 Methods: 2;
Class 3 Methods: 2;
Resolving local member refs: 5 -> 5 defs, 0 refs, 0 unresolved

Emitting events and properties:
Global
Class 1
Class 2
Class 3
Resolving local member refs: 0 -> 0 defs, 0 refs, 0 unresolved
Writing PE file
Operation completed successfully

이제 원하는대로 다형성이 무시된 base 메서드만을 호출하게 동작합니다. ^^

C:\Users\bin\Debug>test
BaseClass.Do




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 4/21/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... [46]  47  48  49  50  51  52  53  54  55  56  57  58  59  60  ...
NoWriterDateCnt.TitleFile(s)
12832정성태9/6/202118103VC++: 149. Golang - 인터페이스 포인터가 의미 있을까요?
12831정성태9/6/202113902VC++: 148. Golang - 채널에 따른 다중 작업 처리파일 다운로드1
12830정성태9/6/202119521오류 유형: 761. Internet Explorer에서 파일 다운로드 시 "Your current security settings do not allow this file to be downloaded." 오류
12829정성태9/5/202120425.NET Framework: 1115. C# 10 - (14) 구조체 타입에 기본 생성자 정의 가능파일 다운로드1
12828정성태9/4/202116962.NET Framework: 1114. C# 10 - (13) 단일 파일 내에 적용되는 namespace 선언파일 다운로드1
12827정성태9/4/202118107스크립트: 27. 파이썬 - 웹 페이지 데이터 수집을 위한 scrapy Crawler 사용법 요약
12826정성태9/3/202122268.NET Framework: 1113. C# 10 - (12) 문자열 보간 성능 개선 [1]파일 다운로드1
12825정성태9/3/202117180개발 환경 구성: 603. GoLand - WSL 환경과 연동
12824정성태9/2/202126477오류 유형: 760. 파이썬 tensorflow - Dst tensor is not initialized. 오류 메시지
12823정성태9/2/202116437스크립트: 26. 파이썬 - PyCharm을 이용한 fork 디버그 방법
12822정성태9/1/202121573오류 유형: 759. 파이썬 tensorflow - ValueError: Shapes (...) and (...) are incompatible [2]
12821정성태9/1/202115863.NET Framework: 1112. C# - .NET 6부터 공개된 ISpanFormattable 사용법
12820정성태9/1/202118089VC++: 147. Golang - try/catch에 대응하는 panic/recover [1]파일 다운로드1
12819정성태8/31/202118441.NET Framework: 1111. C# - FormattableString 타입
12818정성태8/31/202115057Windows: 198. 윈도우 - 작업 관리자에서 (tensorflow 등으로 인한) GPU 연산 부하 보는 방법
12817정성태8/31/202119005스크립트: 25. 파이썬 - 윈도우 환경에서 directml을 이용한 tensorflow의 AMD GPU 사용 방법
12816정성태8/30/202125855스크립트: 24. 파이썬 - tensorflow 2.6 NVidia GPU 사용 방법 [2]
12815정성태8/30/202117298개발 환경 구성: 602. WSL 2 - docker-desktop-data, docker-desktop (%LOCALAPPDATA%\Docker\wsl\data\ext4.vhdx) 파일을 다른 디렉터리로 옮기는 방법
12814정성태8/30/202122765.NET Framework: 1110. C# 11 - 인터페이스 내에 정적 추상 메서드 정의 가능 (DIM for Static Members) [2]파일 다운로드1
12813정성태8/29/202119446.NET Framework: 1109. C# 10 - (11) Lambda 개선파일 다운로드1
12812정성태8/28/202118646.NET Framework: 1108. C# 10 - (10) 개선된 #line 지시자
12811정성태8/27/202118592Linux: 44. 윈도우 개발자를 위한 리눅스 fork 동작 방식 설명 (파이썬 코드)
12810정성태8/27/202118034.NET Framework: 1107. .NET Core/5+에서 동적 컴파일한 C# 코드를 (Breakpoint도 활용하며) 디버깅하는 방법 - #line 지시자파일 다운로드1
12809정성태8/26/202117104.NET Framework: 1106. .NET Core/5+에서 C# 코드를 동적으로 컴파일/사용하는 방법 [1]파일 다운로드1
12808정성태8/25/202119660오류 유형: 758. go: ...: missing go.sum entry; to add it: go mod download ...
12807정성태8/25/202120519.NET Framework: 1105. C# 10 - (9) 비동기 메서드가 사용할 AsyncMethodBuilder 선택 가능파일 다운로드1
... [46]  47  48  49  50  51  52  53  54  55  56  57  58  59  60  ...