성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] A graphical depiction of the steps ...
[정성태] 질문을 주셔서 출판사 측에 문의를 했습니다. 약 한 달 정도 후...
[Thorondor
] @정성태 개인 블로그인데도 거의 커뮤니티 급 인 것 같아요. 요...
[정성태] Roll A Lisp In C - Reading ; https...
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>override 메서드가 정의된 타입의 인스턴스로 base 메서드를 호출하는 방법</h1> <p> 말이 좀 어렵군요. 코드로 설명하는 것이 빠르겠지요? ^^ 다음과 같은 코드가 있을 때,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System; using System.Reflection; using System.Reflection.Emit; 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(); } } } </pre> <br /> 실행하면 화면에는 다음과 같은 출력 결과가 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > DerivedClass.Do BaseClass.Do </pre> <br /> 그런데, DerivedClass.Do 메서드의 작업을 base.Do만 실행하도록 하는 방법은 없을까요? 당연히 virtual/override 메서드이기 때문에 다음과 같이 호출하는 것은 의도한 대로 동작하지 않습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > BaseClass dc = new DerivedClass(); dc.Do(); </pre> <br /> 또한, 리플렉션을 어설프게 이용하는 수준으로는 마찬가지 결과만 얻게 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > MethodInfo mi = typeof(BaseClass).GetMethod("Do"); mi.Invoke(dc, null); </pre> <br /> 혹시나 싶어 검색을 해보았는데, 이미 누군가가 C# 3.0의 확장 메서드로 친절하게 만들어 놓았습니다. ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Invoke base method using reflection ; <a target='tab' href='http://www.simplygoodcode.com/2012/08/invoke-base-method-using-reflection.html'>http://www.simplygoodcode.com/2012/08/invoke-base-method-using-reflection.html</a> </pre> <br /> 위의 글에 공개된 소스코드는 다음과 같습니다.<br /> <br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > public static object InvokeNotOverride(this MethodInfo methodInfo, object targetObject, params object[] arguments) { var parameters = methodInfo.GetParameters(); if (parameters.Length == 0) { if (arguments != null && arguments.Length != 0) throw new Exception("Arguments cont doesn't match"); } else { if (parameters.Length != arguments.Length) throw new Exception("Arguments cont doesn't match"); } Type returnType = null; if (methodInfo.ReturnType != typeof(void)) { returnType = methodInfo.ReturnType; } var type = targetObject.GetType(); var dynamicMethod = new DynamicMethod("", returnType, new Type[] { type, typeof(Object) }, type); var iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); // this for (var i = 0; i < parameters.Length; i++) { var parameter = parameters[i]; iLGenerator.Emit(OpCodes.Ldarg_1); // load array argument // get element at index iLGenerator.Emit(OpCodes.Ldc_I4_S, i); // specify index iLGenerator.Emit(OpCodes.Ldelem_Ref); // get element var parameterType = parameter.ParameterType; if (parameterType.IsPrimitive) { iLGenerator.Emit(OpCodes.Unbox_Any, parameterType); } else if (parameterType == typeof(object)) { // do nothing } else { iLGenerator.Emit(OpCodes.Castclass, parameterType); } } iLGenerator.Emit(<span style='color: blue; font-weight: bold'>OpCodes.Call, methodInfo</span>); iLGenerator.Emit(OpCodes.Ret); return dynamicMethod.Invoke(null, new object[] { targetObject, arguments }); } </pre> <br /> 원리는 간단합니다. 런타임 시에 메서드를 바인딩하는 OpCodes.Callvirt 호출을 사용하지 않고 BaseClass.Do 메서드의 Handle 값을 그대로 OpCodes.Call 코드로 전달해 호출하는 동적 메서드를 만든 것입니다.<br /> <br /> 멋지군요. ^^ (<a target='tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=816&boardid=331301885'>첨부 파일은 위의 예제코드</a>를 테스트 한 것입니다.)<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>s
첨부파일
스팸 방지용 인증 번호
7167
(왼쪽의 숫자를 입력해야 합니다.)