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

C# - 실행 시점에 동적으로 Delegate 타입을 만드는 방법

예를 들어, 다음과 같이 delegate 타입을 만들 수 있는데요,

using System;

public delegate void ActionDelegate(object obj);

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(typeof(ActionDelegate).FullName);
    }
}

C#의 delegate 예약어 덕분에 ActionDelegate가 단순히 선언문 정도로 여겨질 수 있지만, C# 컴파일러는 내부적으로 이를 확장해 System.MulticastDelegate 타입을 상속받는 타입으로 정의를 합니다.

그래서, 실행 시(runtime)에 delegate 타입을 만들고 싶다면 C# 문법에서 지원하는 약식 코드인 "public delegate void ActionDelegate(object obj);" 방식으로는 불가능하고 실제 타입을 만드는 과정 그대로 진행을 해야 합니다. 이와 관련해서 다음의 repo에 delegate 타입을 만드는 코드를 찾을 수 있습니다.

Phalanger/Source/Core/Emit/DelegateBuilder.cs /
; https://github.com/DEVSENSE/Phalanger/blob/master/Source/Core/Emit/DelegateBuilder.cs

위의 소스 코드를 추려 다음과 같이 ActionDelegate와 같은 형식의 타입을 새로 만들 수 있습니다.

AssemblyName myAssemblyName = new AssemblyName();
myAssemblyName.Name = "EmittedAssembly_" + Guid.NewGuid().ToString();
AssemblyBuilder myAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(myAssemblyName,
    AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = myAssembly.DefineDynamicModule("EmittedModule");

Type myActionDelegate2 = CreateDelegateType(moduleBuilder, new Type[] { typeof(object), typeof(void) }, "MyActionDelegate");
Console.WriteLine(myActionDelegate2.FullName); // 출력 결과 MyActionDelegate

public static readonly Type[] DelegateCtorSignature = new Type[] { typeof(object), typeof(IntPtr) };

private static Type CreateDelegateType(ModuleBuilder moduleBuilder, Type[] types, string delegateTypeName)
{
    TypeBuilder typeBuilder = moduleBuilder.DefineType(delegateTypeName, TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.AutoClass, typeof(MulticastDelegate));

    Type returnType = types[types.Length - 1];
    Type[] parameterTypes = types.Take(types.Length - 1).ToArray(); // Array.RemoveLast<Type>(types);

    typeBuilder.DefineConstructor(MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName, CallingConventions.Standard, DelegateCtorSignature).SetImplementationFlags(MethodImplAttributes.CodeTypeMask);
    typeBuilder.DefineMethod("Invoke", MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.VtableLayoutMask, returnType, parameterTypes).SetImplementationFlags(MethodImplAttributes.CodeTypeMask);
    return typeBuilder.CreateType();
}

좀 코드가 많죠? ^^ 위와는 다르지만, 결국 같은 delegate 타입을 만드는 방법이 Expression.GetDelegateType으로 제공이 됩니다. 따라서 이를 활용하면 다음과 같이 간단하게 델리게이트 타입을 동적으로 만들 수 있습니다.

Type myActionDelegate3 = Expression.GetDelegateType(new Type[] { typeof(object), typeof(void) });
Console.WriteLine(myActionDelegate3.FullName);

/* 출력 결과
System.Action`1[[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
*/

보는 바와 같이 Expression.GetDelegateType의 경우, 타입을 새로 만드는 것은 아니고 System.Action에 묻어가는 형식으로 델리게이트 타입을 반환합니다.

(첨부 파일은 이 글의 예제 코드를 포함합니다.)




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







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

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

비밀번호

댓글 작성자
 




... [121]  122  123  124  125  126  127  128  129  130  131  132  133  134  135  ...
NoWriterDateCnt.TitleFile(s)
10933정성태4/5/201631806.NET Framework: 571. C# - 스레드 선호도(Thread Affinity) 지정하는 방법 [8]파일 다운로드1
10932정성태4/4/201624449VC++: 96. C/C++ 식 평가 - printf("%d %d %d\n", a, a++, a);
10931정성태3/31/201624842개발 환경 구성: 283. Hyper-V 내에 구성한 Active Directory 환경의 시간 구성 방법 [3]
10930정성태3/30/201622878.NET Framework: 570. .NET 4.5부터 추가된 CLR Profiler의 실행 시 Rejit 기능
10929정성태3/29/201633133.NET Framework: 569. ServicePointManager.DefaultConnectionLimit의 역할파일 다운로드1
10928정성태3/28/201638854.NET Framework: 568. ODP.NET의 완전한 닷넷 버전 Oracle ODP.NET, Managed Driver [2]파일 다운로드1
10927정성태3/25/201627334.NET Framework: 567. System.Net.ServicePointManager의 DefaultConnectionLimit 속성 설명
10926정성태3/24/201627623.NET Framework: 566. openssl의 PKCS#1 PEM 개인키 파일을 .NET RSACryptoServiceProvider에서 사용하는 방법 [10]파일 다운로드1
10925정성태3/24/201621253.NET Framework: 565. C# - Rabin-Miller 소수 생성 방법을 이용하여 RSACryptoServiceProvider의 개인키를 직접 채워보자 - 두 번째 이야기파일 다운로드1
10924정성태3/22/201622529오류 유형: 324. Visual Studio에서 Azure 클라우드 서비스 생성 시 Failed to initialize the PowerShell host 에러 발생
10923정성태3/21/201622862.NET Framework: 564. C# - DGML로 바이너리 트리 출력하는 방법 [1]파일 다운로드1
10922정성태3/21/201624005.NET Framework: 563. 디버깅 용도로 이진 트리의 내용을 출력하는 방법파일 다운로드1
10921정성태3/17/201627290.NET Framework: 562. BBI 인터프리터 C/C++ 코드를 C#으로 변환 [3]파일 다운로드2
10920정성태3/15/201627923.NET Framework: 561. null 처리된 객체가 왜 GC에 의해 수집되지 않을까요? [6]파일 다운로드1
10919정성태3/12/201624160.NET Framework: 560. C#에서 return할 때 명시적으로 casting한 것과 안한 것의 차이 [2]파일 다운로드1
10918정성태3/10/201621135.NET Framework: 559. WPF - ICommand.CanExecuteChanged가 해제되지 않는 문제 [2]파일 다운로드1
10917정성태3/10/201641103.NET Framework: 558. WPF - ICommand 동작 방식 [9]파일 다운로드1
10916정성태3/9/201628181.NET Framework: 557. 머신 바이트 배열로부터 역어셈블해주는 라이브러리 - Udis86 Assembler파일 다운로드2
10915정성태3/9/201623253오류 유형: 323. FatalExecutionEngineError was detected
10914정성태3/8/201626654오류 유형: 322. 정적 라이브러리 참조 시 "LNK2019 unresolved external symbol '...' referenced in function" 오류 발생파일 다운로드1
10913정성태3/7/201626443.NET Framework: 556. C#으로 다루는 MBR(Master Boot Record) [9]파일 다운로드1
10912정성태3/2/201622621.NET Framework: 555. List<T>의 Resize 메서드 구현 [2]파일 다운로드1
10911정성태2/29/201626609Math: 15. 그래프 그리기로 알아보는 뉴턴-랩슨(Newton-Raphson's method)법과 제곱근 구하기 - C#파일 다운로드1
10910정성태2/29/201628455Math: 14. HTML에서 수학 관련 기호/수식을 표현하기 위한 방법 - MathJax.js - 두 번째 이야기 [5]
10909정성태2/25/201626703기타: 56. ETW provider 목록 [3]
10908정성태2/25/201622885기타: 55. ETW man 파일 목록
... [121]  122  123  124  125  126  127  128  129  130  131  132  133  134  135  ...