Creative Commons License

Microsoft .NET

닷넷!시작하기
닷넷! Ver 2.0~
닷넷!스킬업
웹개발
윈폼개발
실용모듈개발
Tip & Tech
하루 한 문법

Microsoft .NET 개발자들을 위한 공간입니다. 기초강의에서 부터 고급 기술 정보 및 팁등을 다루도록 하겠습니다.

.

닷넷!스킬업

닷넷 기술을 조금 더 깊이 다루고자 합니다. 특정 주제를 정하지 않고 이슈 발생 시 마다 체계적으로 정리하여 공유하겠습니다. 이전 자료를 옮겨온 곳이기도 합니다.

Reflection (리플렉션)

작성자 : 박종명
최초 작성일 : 2008-06-16 (월요일)
최종 수정일 : 2008-06-16 (월요일)
조회 수 : 3422

* Reflection 개요

사전적인 의미로 Reflection 반사,투영,반향 으로 해석된다.
프로그래밍 측면에서 보면 Reflection 어셈블리 파일 또는 메모리에 로드 된 객체로부터
각종 정보(클래스,메서드,속성등)를 얻을 수 있고 동적으로 클래스의 인스턴스  생성 및 메서드 호출을 가능케 하는 프로그램 기법을 말한다.

 

System.Reflection 네임스페이스 하위에 정의된 각종 클래스를 이용하여 다음과 같은 작업을 할 수 있다.

1. 어셈블리 파일(exe,dll)에 포함된 클래스 정보 및 어트리뷰트 정보들을 추출

2. 클래스에 정의된 메서드 정보 추출 및 호출,속성 정보 추출 및 속성 값 조회 및 설정

3. (클래스) 타입을 알지 못하는 객체(메모리에 로드된 클래스의 인스턴스)에 대한 멤버
   (속성,메서드,생성자등)를 검사 및 호출

 

4. 동적 객체 생성 : 객체를 new 타입() 으로 생성하는 것이 아니라 클래스명(string)으로 객체(인스턴스) 생성

5. 기타 어셈블리에 관련한 거의 모든 정보 추출

6. Emit 서비스를 이용해 직접 어셈블리와 형식을 내보내기

 

다음은 MSDN 에 정의된 Reflection 개요와 관련 클래스에 대한 설명이다.

공용 언어 런타임 로더는 응용 프로그램 도메인을 관리합니다. 이 관리 작업에는 각 어셈블리를 적절한 응용 프로그램 도메인에 로드하고 각 어셈블리에 있는 형식 계층 구조의 메모리 레이아웃을 제어하는 일이 포함됩니다.

어셈블리에는 모듈이 있고, 모듈에는 형식이 있으며, 형식에는 멤버가 있습니다. 리플렉션을 통해 어셈블리, 모듈 및 형식을 캡슐화하는 개체를 제공할 수 있습니다. 리플렉션을 사용하여 형식의 인스턴스를 동적으로 만들거나, 형식을 기존 개체에 바인딩하거나, 기존 개체에서 형식을 가져올 수 있습니다. 그리고 나서 형식의 메서드를 호출하거나 형식의 필드 및 속성에 액세스할 수 있습니다. 리플렉션의 일반적인 용도는 다음과 같습니다.

·                 Assembly를 사용하여 어셈블리를 정의 및 로드하고, 어셈블리 매니페스트에 나열된 모듈을 로드하며, 이 어셈블리에서 형식을 찾아 형식의 인스턴스를 만듭니다.

·                 Module을 사용하여 모듈이 포함된 어셈블리와 모듈에 있는 클래스 등의 정보를 검색합니다. 모든 전역 메서드를 가져오거나 모듈에 정의된 다른 특정 비전역 메서드를 가져올 수도 있습니다.

·                 ConstructorInfo를 사용하여 생성자의 이름, 매개 변수, public 또는 private 같은 액세스 한정자, 추상 또는 가상 같은 구현 정보를 검색합니다. TypeGetConstructors 또는 GetConstructor 메서드를 사용하여 특정 생성자를 호출합니다.

·                 MethodInfo를 사용하여 메서드의 이름, 반환 형식, 매개 변수, public 또는 private 같은 액세스 한정자, 추상 또는 가상 같은 구현 정보를 검색합니다. TypeGetMethods 또는 GetMethod 메서드를 사용하여 특정 메서드를 호출합니다.

·                 FieldInfo를 사용하여 필드의 이름, 액세스 정자, public 또는 private 같은 액세스 한정자, static 같은 구현 정보를 검색하고, 필드 값을 가져오거나 설정합니다.

·                 EventInfo를 사용하여 이벤트의 이름, 이벤트 처리기 데이터 형식, 사용자 지정 특성, 형식 선언 및 리플렉션된 형식 같은 정보를 검색하고, 이벤트 처리기를 추가하거나 제거합니다.

·                 PropertyInfo를 사용하여 속성의 이름, 데이터 형식, 선언 형식, 리플렉션된 형식 및 읽기 전용/쓰기 가능 상태 같은 정보를 검색하고, 속성 값을 가져오거나 설정합니다.

·                 ParameterInfo를 사용하여 매개 변수의 이름, 데이터 형식, 입력 매개 변수인지 출력 매개 변수인지 여부 및 메서드 시그니처의 매개 변수 위치 같은 정보를 검색합니다.

System.Reflection.Emit 네임스페이스의 클래스에서는 런타임에 형식을 만들 수 있도록 하는 리플렉션의 특수 형식을 제공합니다.

리플렉션은 형식 브라우저라고 하는 응용 프로그램을 만드는 데도 사용될 수 있습니다. 형식 브라우저를 사용하면 형식을 선택하고 선택된 형식에 대한 정보를 있습니다.

리플렉션에는 다른 용도도 있습니다. JScript 같은 언어의 컴파일러에서는 기호 테이블을 만드는 리플렉션이 사용됩니다. System.Runtime.Serialization 네임스페이스의 클래스에서는 리플렉션을 사용하여 데이터에 액세스하고 유지할 필드를 결정합니다. System.Runtime.Remoting 네임스페이스의 클래스에서는 serialization 통해 간접적으로 리플렉션을 사용합니다.

 

 

 

간단하게 말하자면 Reflection 은 물리적인 어셈블리 파일로부터 형식정보를 얻거나 메모리에 로드 된 클래스의 인스턴스로 부터 역으로 형식정보를 얻어와서 형식에 대한 각종 조사 및 호출,가공,조작,동적 인스턴스 생성등을 할 수 있게 하는 프로그래밍 기법이라 정리할 수 있겠다.

 

* Demo

System.Reflection 네임스페이스에는 중요한 클래스들이 있으며 각 클래스 또한 많은 멤버를 포함하고 있다.

이를 하나하나 살펴보기란 쉽지 않음으로 유용한 예제 코드를 살펴 보도록 한다. Reflection 을 이용한 데모를 살펴봄으로써 그 용도를 파악하고 Reflection 의 진정한 의미를 되새겨 보자.

 

- Demo 설명 -

이번 Demo 에서는 System.Reflection 관련 클래스들을 사용해서 어셈블리의 각종 정보를 검사하고 각 정보를 호출,조회,설정들을 해 보는 예제이다. , 컴퓨터에 저장된 특정 닷넷 어셈블리(exe,dll) 를 선택하면 그 어셈블리에 대한 조사를 수행하게 된다.

일단 데모를 실행한 캡쳐 화면을 보면 이 데모가 무엇을 하는 넘인지 알 수 있을 것이다



데모 실행 화면에 나타 나듯이 임의의 닷넷 어셈블리를 선택하여 Load 하면 그 어셈블리에 정의된 네임스페이스,델리게이트,클래스,속성,메서드,생성자,구조체 등을 조사할 수 있으며 나아가 메서드의 호출 및 속성값을 알 수 있다.

 위의 그림에서 메세지 박스는 Method1_public 를 호출한 결과이다.

 

 아래는 Reflection 관련 클래스로 어셈블리 조사를 수행하는 클래스 코드이다. 주석으로 웬만한 설명을 기입했으므로 별도의 구차한(?) 설명을 생략하도록 한다.  첨부한 파일을 다운 받아서 실제로 실행해 보기를 바란다.

 

using System;

using System.Reflection;

 

namespace ReflectionDemo

{           

             public class Reflector

             {                        

                           private Assembly assembly;                         

 

                           public Reflector(){}

                           public Reflector(string assemblyFullPath)

                           {

                                        //외부 어셈블리일 경우에는 어셈블리로 부터 타입을 얻어야 한다.

                                        //Assembly.LoadFrom(assemblyFullPath).GetType("네임스페이스.클래스");

                                        //만일 현재 실행되는 어셈블리에 포함된 타입을 얻을 경우에는 아래처럼만 하면 된다

                                        //Type type = Type.GetType(className)                                

                                        this.assembly = Assembly.LoadFrom(assemblyFullPath);

                                       

                                        //Default 생성자를 이용하여 동적 인스턴스 생성

                                        //만일 매개변수가 있는 생성자를 호출할 경우에는 object 배열을 파라메타로 전달

                                        //Activator.CreateInstance(type,new object[]{매개변수1,매개변수2})

                                        //this.obj = Activator.CreateInstance(type);                               

                           }

 

                           #region 클래스 정보

                           public System.Type[] GetClassInfos()

                           {                                     

                                        Type[] types = this.assembly.GetTypes();                               

                                        return types;

                           }                        

                           #endregion

 

                           #region 생성자 정보

                           public ConstructorInfo[] GetConstructorInfos(string className)

                           {

                                        Type type = assembly.GetType(className);                                                                   

                                        System.Reflection.ConstructorInfo[] constructorInfos = type.GetConstructors();                                  

                                        return constructorInfos;

                           }                        

                           #endregion

 

                           #region 메서드 정보

                           public MethodInfo[] GetMethodInfos(string className)

                           {                                     

                                   Type type = this.assembly.GetType(className);  

                                   System.Reflection.MethodInfo[] methodInfos =

                                           type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | 
                                                                                                                   BindingFlags.Instance);  

                                   return methodInfos;                                      

                           }                        

                           #endregion

 

                           #region 필드 정보

                           public FieldInfo[] GetFieldInfos(string className)

                           {

                                   Type type = this.assembly.GetType(className);                                   

                                   System.Reflection.FieldInfo[] fieldInfos =

                                                     type.GetFields(BindingFlags.Public | BindingFlags.NonPublic |
                                                                                                                    BindingFlags.Instance);

                                   return fieldInfos;

                           }                        

                           #endregion

 

                           #region 속성값 알아내기

                           public object GetFieldValue(string className,string fieldName)

                           {

                                        Type type = this.assembly.GetType(className);

                                        Object obj = Activator.CreateInstance(type);    

                                        FieldInfo f = type.GetField(fieldName, BindingFlags.Public | 
                                                  BindingFlags.NonPublic | indingFlags.Instance); 

                                        return f.GetValue(obj);                                                                          

                           }

                           #endregion

 

                           #region 메서드 호출하기

                           public object GetReturnValueOfMethod(string className,string methodName)

                           {

                                       

                                       Type type = this.assembly.GetType(className);

                                       Object obj = Activator.CreateInstance(type);    

                                       MethodInfo m = type.GetMethod(methodName, BindingFlags.Public |
                                                                       BindingFlags.NonPublic | BindingFlags.Instance);

                                       //String 타입 매개변수 하나를 받는 메서드 호출

                                       return m.Invoke(obj,new object[]{"아무거나"});             

                           }

                           #endregion

             }

}

 

이름
비밀번호
홈페이지
UJ <- 왼쪽의 문자를 오른쪽 박스에 똑같이 입력해 주세요