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

비밀번호

댓글 작성자
 




... 31  32  33  34  [35]  36  37  38  39  40  41  42  43  44  45  ...
NoWriterDateCnt.TitleFile(s)
12781정성태8/14/20219361오류 유형: 755. 파이썬 - konlpy 사용 시 JVM과 jpype1 관련 오류
12780정성태8/13/20217716.NET Framework: 1088. C# - 버스 노선 및 위치 정보 조회 API 사용을 위한 기초 라이브러리 [2]
12779정성태8/13/20219631개발 환경 구성: 596. 공공 데이터 포털에서 버스 노선 및 위치 정보 조회 API 사용법
12778정성태8/12/20216760오류 유형: 755. PyCharm - "Manage Repositories"의 목록이 나오지 않는 문제
12777정성태8/12/20218333오류 유형: 754. Visual Studio - Input or output cannot be redirected because the specified file is invalid.
12776정성태8/12/20217609오류 유형: 753. gunicorn과 uwsgi 함께 사용 시 ERR_CONNECTION_REFUSED
12775정성태8/12/202119509스크립트: 22. 파이썬 - 윈도우 환경에서 개발한 Django 앱을 WSL 환경의 gunicorn을 이용해 실행
12774정성태8/11/20219320.NET Framework: 1087. C# - Collection 개체의 다중 스레드 접근 시 "Operations that change non-concurrent collections must have exclusive access" 예외 발생
12773정성태8/11/20218541개발 환경 구성: 595. PyCharm - WSL과 연동해 Django App을 윈도우에서 리눅스 대상으로 개발
12772정성태8/11/20219989스크립트: 21. 파이썬 - 윈도우 환경에서 개발한 Django 앱을 WSL 환경의 uwsgi를 이용해 실행 [1]
12771정성태8/11/20218387Windows: 196. "Microsoft Windows Subsystem for Linux Background Host" / "Vmmem"을 종료하는 방법
12770정성태8/11/20219274.NET Framework: 1086. C# - Windows Forms 응용 프로그램의 자식 컨트롤 부하파일 다운로드1
12769정성태8/11/20216981오류 유형: 752. Python - ImportError: No module named pip._internal.cli.main 두 번째 이야기
12768정성태8/10/20218151.NET Framework: 1085. .NET 6에 포함된 신규 BCL API [1]파일 다운로드1
12767정성태8/10/20219252오류 유형: 752. Python - ImportError: No module named pip._internal.cli.main
12766정성태8/9/20217645Java: 32. closing inbound before receiving peer's close_notify
12765정성태8/9/20217001Java: 31. Cannot load JDBC driver class 'org.mysql.jdbc.Driver'
12764정성태8/9/202145456Java: 30. XML document from ServletContext resource [/WEB-INF/applicationContext.xml] is invalid
12763정성태8/9/20218516Java: 29. java.lang.NullPointerException - com.mysql.jdbc.ConnectionImpl.getServerCharset
12762정성태8/8/202112134Java: 28. IntelliJ - Unable to open debugger port 오류
12761정성태8/8/20219207Java: 27. IntelliJ - java: package javax.inject does not exist [2]
12760정성태8/8/20216517개발 환경 구성: 594. 전용 "Command Prompt for ..." 단축 아이콘 만들기
12759정성태8/8/20219767Java: 26. IntelliJ + Spring Framework + 새로운 Controller 추가 [2]파일 다운로드1
12758정성태8/7/20219105오류 유형: 751. Error assembling WAR: webxml attribute is required (or pre-existing WEB-INF/web.xml if executing in update mode)
12757정성태8/7/20219798Java: 25. IntelliJ + Spring Framework 프로젝트 생성
12756정성태8/6/20218525.NET Framework: 1084. C# - .NET Core Web API 단위 테스트 방법 [1]파일 다운로드1
... 31  32  33  34  [35]  36  37  38  39  40  41  42  43  44  45  ...