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

비밀번호

댓글 작성자
 




1  2  3  4  5  6  [7]  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13804정성태11/7/20247071Linux: 101. eBPF 함수의 인자를 다루는 방법
13803정성태11/7/20246650닷넷: 2309. C# - .NET Core에서 바뀐 DateTime.Ticks의 정밀도
13802정성태11/6/20247057Windows: 269. GetSystemTimeAsFileTime과 GetSystemTimePreciseAsFileTime의 차이점파일 다운로드1
13801정성태11/5/20246871Linux: 100. eBPF의 2가지 방식 - libbcc와 libbpf(CO-RE)
13800정성태11/3/20247848닷넷: 2308. C# - ICU 라이브러리를 활용한 문자열의 대소문자 변환 [2]파일 다운로드1
13799정성태11/2/20245616개발 환경 구성: 732. 모바일 웹 브라우저에서 유니코드 문자가 표시되지 않는 경우
13798정성태11/2/20247277개발 환경 구성: 731. 유니코드 - 출력 예시 및 폰트 찾기
13797정성태11/1/20247265C/C++: 185. C++ - 문자열의 대소문자를 변환하는 transform + std::tolower/toupper 방식의 문제점파일 다운로드1
13796정성태10/31/20246776C/C++: 184. C++ - ICU dll을 이용하는 예제 코드 (Windows)파일 다운로드1
13795정성태10/31/20245967Windows: 268. Windows - 리눅스 환경처럼 공백으로 끝나는 프롬프트 만들기
13794정성태10/30/20246049닷넷: 2307. C# - 윈도우에서 한글(및 유니코드)을 포함한 콘솔 프로그램을 컴파일 및 실행하는 방법
13793정성태10/28/20246017C/C++: 183. C++ - 윈도우에서 한글(및 유니코드)을 포함한 콘솔 프로그램을 컴파일 및 실행하는 방법
13792정성태10/27/20245404Linux: 99. Linux - 프로세스의 실행 파일 경로 확인
13791정성태10/27/20245862Windows: 267. Win32 API의 A(ANSI) 버전은 DBCS를 사용할까요?파일 다운로드1
13790정성태10/27/20245369Linux: 98. Ubuntu 22.04 - 리눅스 커널 빌드 및 업그레이드
13789정성태10/27/20246332Linux: 97. menuconfig에 CONFIG_DEBUG_INFO_BTF, CONFIG_DEBUG_INFO_BTF_MODULES 옵션이 없는 경우
13788정성태10/26/20245134Linux: 96. eBPF (bpf2go) - fentry, fexit를 이용한 트레이스
13787정성태10/26/20246492개발 환경 구성: 730. github - Linux 커널 repo를 윈도우 환경에서 git clone하는 방법 [1]
13786정성태10/26/20246266Windows: 266. Windows - 대소문자 구분이 가능한 파일 시스템
13785정성태10/23/20245623C/C++: 182. 윈도우가 운영하는 2개의 Code Page파일 다운로드1
13784정성태10/23/20246225Linux: 95. eBPF - kprobe를 이용한 트레이스
13783정성태10/23/20245742Linux: 94. eBPF - vmlinux.h 헤더 포함하는 방법 (bpf2go에서 사용)
13782정성태10/23/20245423Linux: 93. Ubuntu 22.04 - 커널 이미지로부터 커널 함수 역어셈블
13781정성태10/22/20245982오류 유형: 930. WSL + eBPF: modprobe: FATAL: Module kheaders not found in directory
13780정성태10/22/20247037Linux: 92. WSL 2 - 커널 이미지로부터 커널 함수 역어셈블
13779정성태10/22/20245609개발 환경 구성: 729. WSL 2 - Mariner VM 커널 이미지 업데이트 방법
1  2  3  4  5  6  [7]  8  9  10  11  12  13  14  15  ...