연습: 관리되는 어셈블리의 형식 포함(C# 및 Visual Basic)
강력한 이름의 관리되는 어셈블리에 있는 형식 정보를 포함하면 응용 프로그램의 형식을 느슨하게 결합하여 버전 독립성을 이룰 수 있습니다.즉, 각 버전에 대해 다시 컴파일하지 않고도 여러 버전의 관리되는 라이브러리에 있는 형식을 사용하는 프로그램을 작성할 수 있습니다.
형식 포함은 Microsoft Office의 자동화 개체를 사용하는 응용 프로그램 같은 COM interop에서 자주 사용됩니다.형식 정보를 포함하면 동일한 빌드의 프로그램이 서로 다른 컴퓨터에서 여러 버전의 Microsoft Office와 함께 작동하도록 할 수 있습니다.또한 완전하게 관리되는 솔루션에서 형식 포함을 사용할 수도 있습니다.
포함할 수 있는 형식 정보가 들어 있는 어셈블리에는 다음과 같은 특징이 있습니다.
어셈블리에서 하나 이상의 공용 인터페이스를 노출합니다.
포함된 인터페이스의 주석이 ComImport 특성과 Guid 특성(및 고유 GUID)으로 지정됩니다.
ImportedFromTypeLib 또는 PrimaryInteropAssembly 특성과 어셈블리 수준 Guid 특성을 사용하여 어셈블리에 주석이 지정되어 있습니다.기본적으로 Visual Basic 및 Visual C# 프로젝트 템플릿에는 어셈블리 수준 Guid 특성이 포함되어 있습니다.
포함할 수 있는 공용 인터페이스를 지정한 후에는 이러한 인터페이스를 구현하는 런타임 클래스를 만들 수 있습니다.그러면 클라이언트 프로그램에서 공용 인터페이스가 포함된 어셈블리를 참조하고 참조의 Embed Interop Types 속성을 True로 설정하여 디자인 타임에 이러한 인터페이스의 형식 정보를 포함할 수 있습니다.이는 명령줄 컴파일러를 사용하고 /link 컴파일러 옵션을 통해 어셈블리를 참조하는 것과 같습니다.그러면 클라이언트 프로그램에서 이러한 인터페이스로 형식화된 런타임 개체의 인스턴스를 로드할 수 있습니다.강력한 이름의 런타임 어셈블리 버전을 새로 만드는 경우 클라이언트 프로그램을 업데이트된 런타임 어셈블리로 다시 컴파일하지 않아도 됩니다.대신 클라이언트 프로그램에서 공용 인스턴스의 포함된 형식 정보를 통해 어떤 버전이든 상관없이 사용 가능한 런타임 어셈블리를 계속 사용합니다.
형식 포함의 주된 기능은 COM interop 어셈블리의 형식 정보를 포함하도록 지원하는 것이기 때문에 완전히 관리되는 솔루션에 형식 정보를 포함하는 경우 다음과 같은 제한이 적용됩니다.
COM intero와 관련된 특성만 포함되고 다른 특성은 무시됩니다.
형식에서 제네릭 매개 변수가 사용되고 제네릭 매개 변수의 형식이 포함된 형식인 경우 해당 형식은 어셈블리 경계를 넘어 사용될 수 없습니다.어셈블리 경계를 넘는 경우의 예로는 다른 어셈블리에서 메서드를 호출하거나 다른 어셈블리에 정의된 형식에서 형식을 파생시키는 경우 등이 있습니다.
상수는 포함되지 않습니다.
System.Collections.Generic.Dictionary<TKey, TValue> 클래스에서는 포함된 형식을 키로 지원하지 않습니다.포함된 형식을 키로 지원하려면 고유한 사전 형식을 구현하면 됩니다.
이 연습에서는 다음 작업을 수행합니다.
포함할 수 있는 형식 정보가 들어 있는 공용 인스턴스를 가진 강력한 이름의 어셈블리를 만듭니다.
공용 인터페이스를 구현하는 강력한 이름의 런타임 어셈블리를 만듭니다.
공용 인터페이스의 형식 정보를 포함하고 런타임 어셈블리의 클래스 인스턴스를 만드는 클라이언트 프로그램을 만듭니다.
런타임 어셈블리를 수정하고 다시 빌드합니다.
클라이언트 프로그램을 실행하여 클라이언트 프로그램을 다시 컴파일하지 않고도 새 버전의 런타임 어셈블리가 사용되고 있는지 확인합니다.
[!참고]
다음 지침처럼 컴퓨터에서 Visual Studio 사용자 인터페이스 요소 일부에 대한 이름이나 위치를 다르게 표시할 수 있습니다. 이러한 요소는 사용하는 Visual Studio 버전 및 설정에 따라 결정됩니다. 자세한 내용은 Visual Studio 설정을 참조하십시오.
인터페이스 만들기
형식이 동일한 인터페이스 프로젝트를 만들려면
Visual Studio의 파일 메뉴에서 새로 만들기를 가리킨 다음 프로젝트를 클릭합니다.
새 프로젝트 대화 상자의 프로젝트 형식 창에서 Windows가 선택되었는지 확인합니다.템플릿 창에서 클래스 라이브러리를 선택합니다.이름 상자에 TypeEquivalenceInterface를 입력한 다음 확인을 클릭합니다.새 프로젝트가 만들어집니다.
솔루션 탐색기에서 Class1.vb 또는 Class1.cs 파일을 마우스 오른쪽 단추로 클릭한 다음 이름 바꾸기를 클릭합니다.파일의 이름을 ISampleInterface.vb 또는 ISampleInterface.cs로 바꾸고 Enter 키를 누릅니다.파일의 이름을 바꾸면 클래스의 이름도 ISampleInterface로 바뀝니다.이 클래스는 클래스의 공용 인터페이스를 나타납니다.
TypeEquivalenceInterface 프로젝트를 마우스 오른쪽 단추로 클릭하고 속성을 클릭합니다.Visual Basic에서 컴파일 탭 또는 Visual C#에서 빌드 탭을 클릭합니다.출력 경로를 C:\TypeEquivalenceSample과 같은 개발 컴퓨터의 유효한 위치로 설정합니다.이 위치는 이 연습의 이후 단계에서도 사용됩니다.
프로젝트 속성을 계속 편집하면서 서명 탭을 클릭합니다.어셈블리 서명 옵션을 선택합니다.강력한 이름 키 파일 선택 목록에서 **<새로 만들기...>**를 클릭합니다.키 파일 이름 상자에 key.snk를 입력합니다.암호로 내 키 파일 보호 확인란의 선택을 취소합니다.확인을 클릭합니다.
ISampleInterface.vb 또는 ISampleInterface.cs 파일을 엽니다.ISampleInterface 클래스 파일에 다음 코드를 추가하여 ISampleInterface 인터페이스를 만듭니다.
Imports System.Runtime.InteropServices <ComImport()> <Guid("8DA56996-A151-4136-B474-32784559F6DF")> Public Interface ISampleInterface Sub GetUserInput() ReadOnly Property UserInput As String ... End Interface
using System; using System.Runtime.InteropServices; namespace TypeEquivalenceInterface { [ComImport] [Guid("8DA56996-A151-4136-B474-32784559F6DF")] public interface ISampleInterface { void GetUserInput(); string UserInput { get; } ... } }
도구 메뉴에서 GUID 만들기를 클릭합니다.GUID 만들기 대화 상자에서 레지스트리 형식을 클릭한 다음 복사를 클릭합니다.끝내기를 클릭합니다.
Guid 특성에서 샘플 GUID를 삭제하고 GUID 만들기 대화 상자에서 복사한 GUID를 붙여넣습니다.복사한 GUID에서 중괄호({})를 제거합니다.
Visual Basic의 프로젝트 메뉴에서 모든 파일 표시를 클릭합니다.Visual C#을 사용하는 경우 이 단계를 건너뜁니다.
Visual Basic을 사용하는 경우 솔루션 탐색기에서 My Project 폴더를 확장합니다.Visual C#을 사용하는 경우 Properties 폴더를 확장합니다.AssemblyInfo.vb 또는 AssemblyInfo.cs 파일을 두 번 클릭합니다.파일에 다음 특성을 추가합니다.
<Assembly: ImportedFromTypeLib("")>
[assembly: ImportedFromTypeLib("")]
파일을 저장합니다.
프로젝트를 저장합니다.
TypeEquivalenceInterface 프로젝트를 마우스 오른쪽 단추로 클릭하고 빌드를 클릭합니다.클래스 라이브러리 .dll 파일이 컴파일된 다음 지정된 빌드 출력 경로(예: C:\TypeEquivalenceSample)에 저장됩니다.
런타임 클래스 만들기
형식이 동일한 런타임 프로젝트를 만들려면
Visual Studio의 파일 메뉴에서 새로 만들기를 가리킨 다음 프로젝트를 클릭합니다.
새 프로젝트 대화 상자의 프로젝트 형식 창에서 Windows가 선택되었는지 확인합니다.템플릿 창에서 클래스 라이브러리를 선택합니다.이름 상자에 TypeEquivalenceRuntime을 입력한 다음 확인을 클릭합니다.새 프로젝트가 만들어집니다.
솔루션 탐색기에서 Class1.vb 또는 Class1.cs 파일을 마우스 오른쪽 단추로 클릭한 다음 이름 바꾸기를 클릭합니다.파일의 이름을 SampleClass.vb 또는 SampleClass.cs로 바꾸고 Enter 키를 누릅니다.파일의 이름을 바꾸면 클래스의 이름도 SampleClass로 바뀝니다.이 클래스는 ISampleInterface 인터페이스를 구현합니다.
TypeEquivalenceRuntime 프로젝트를 마우스 오른쪽 단추로 클릭하고 속성을 클릭합니다.Visual Basic에서 컴파일 탭 또는 Visual C#에서 빌드 탭을 클릭합니다.출력 경로를 TypeEquivalenceInterface 프로젝트에 사용한 것과 동일한 위치(예: C:\TypeEquivalenceSample)로 설정합니다.
프로젝트 속성을 계속 편집하면서 서명 탭을 클릭합니다.어셈블리 서명 옵션을 선택합니다.강력한 이름 키 파일 선택 목록에서 **<새로 만들기...>**를 클릭합니다.키 파일 이름 상자에 key.snk를 입력합니다.암호로 내 키 파일 보호 확인란의 선택을 취소합니다.확인을 클릭합니다.
TypeEquivalenceRuntime 프로젝트를 마우스 오른쪽 단추로 클릭하고 참조 추가를 클릭합니다.찾아보기 탭을 클릭하고 출력 경로 폴더를 찾습니다.TypeEquivalenceInterface.dll 파일을 선택하고 확인을 클릭합니다.
Visual Basic의 프로젝트 메뉴에서 모든 파일 표시를 클릭합니다.Visual C#을 사용하는 경우 이 단계를 건너뜁니다.
솔루션 탐색기에서 References 폴더를 확장합니다.TypeEquivalenceInterface 참조를 선택합니다.TypeEquivalenceInterface 참조의 속성 창에서 특정 버전 속성을 False로 설정합니다.
SampleClass 클래스 파일에 다음 코드를 추가하여 SampleClass 클래스를 만듭니다.
Imports TypeEquivalenceInterface Public Class SampleClass Implements ISampleInterface Private p_UserInput As String Public ReadOnly Property UserInput() As String Implements ISampleInterface.UserInput Get Return p_UserInput End Get End Property Public Sub GetUserInput() Implements ISampleInterface.GetUserInput Console.WriteLine("Please enter a value:") p_UserInput = Console.ReadLine() End Sub ... End Class
using System; using System.Collections.Generic; using System.Linq; using System.Text; using TypeEquivalenceInterface; namespace TypeEquivalenceRuntime { public class SampleClass : ISampleInterface { private string p_UserInput; public string UserInput { get { return p_UserInput; } } public void GetUserInput() { Console.WriteLine("Please enter a value:"); p_UserInput = Console.ReadLine(); } ... } }
프로젝트를 저장합니다.
TypeEquivalenceRuntime 프로젝트를 마우스 오른쪽 단추로 클릭하고 빌드를 클릭합니다.클래스 라이브러리 .dll 파일이 컴파일된 다음 지정된 빌드 출력 경로(예: C:\TypeEquivalenceSample)에 저장됩니다.
클라이언트 프로젝트 만들기
형식이 동일한 클라이언트 프로젝트를 만들려면
Visual Studio의 파일 메뉴에서 새로 만들기를 가리킨 다음 프로젝트를 클릭합니다.
새 프로젝트 대화 상자의 프로젝트 형식 창에서 Windows가 선택되었는지 확인합니다.템플릿 창에서 콘솔 응용 프로그램을 선택합니다.이름 상자에 TypeEquivalenceClient를 입력한 다음 확인을 클릭합니다.새 프로젝트가 만들어집니다.
TypeEquivalenceClient 프로젝트를 마우스 오른쪽 단추로 클릭하고 속성을 클릭합니다.Visual Basic에서 컴파일 탭 또는 Visual C#에서 빌드 탭을 클릭합니다.출력 경로를 TypeEquivalenceInterface 프로젝트에 사용한 것과 동일한 위치(예: C:\TypeEquivalenceSample)로 설정합니다.
TypeEquivalenceClient 프로젝트를 마우스 오른쪽 단추로 클릭하고 참조 추가를 클릭합니다.찾아보기 탭을 클릭하고 출력 경로 폴더를 찾습니다.TypeEquivalenceInterface.dll 파일(TypeEquivalenceRuntime.dll 아님)을 선택하고 확인을 클릭합니다.
Visual Basic의 프로젝트 메뉴에서 모든 파일 표시를 클릭합니다.Visual C#을 사용하는 경우 이 단계를 건너뜁니다.
솔루션 탐색기에서 References 폴더를 확장합니다.TypeEquivalenceInterface 참조를 선택합니다.TypeEquivalenceInterface 참조의 속성 창에서 Interop 형식 포함 속성을 True로 설정합니다.
Module1.vb 또는 Program.cs 파일에 다음 코드를 추가하여 클라이언트 프로그램을 만듭니다.
Imports TypeEquivalenceInterface Imports System.Reflection Module Module1 Sub Main() Dim sampleAssembly = Assembly.Load("TypeEquivalenceRuntime") Dim sampleClass As ISampleInterface = CType( _ sampleAssembly.CreateInstance("TypeEquivalenceRuntime.SampleClass"), ISampleInterface) sampleClass.GetUserInput() Console.WriteLine(sampleClass.UserInput) Console.WriteLine(sampleAssembly.GetName().Version) Console.ReadLine() End Sub End Module
using System; using System.Collections.Generic; using System.Linq; using System.Text; using TypeEquivalenceInterface; using System.Reflection; namespace TypeEquivalenceClient { class Program { static void Main(string[] args) { Assembly sampleAssembly = Assembly.Load("TypeEquivalenceRuntime"); ISampleInterface sampleClass = (ISampleInterface)sampleAssembly.CreateInstance("TypeEquivalenceRuntime.SampleClass"); sampleClass.GetUserInput(); Console.WriteLine(sampleClass.UserInput); Console.WriteLine(sampleAssembly.GetName().Version.ToString()); Console.ReadLine(); } } }
Ctrl+F5를 눌러 프로그램을 빌드하고 실행합니다.
인터페이스 수정
인터페이스를 수정하려면
Visual Studio의 파일 메뉴에서 열기를 가리킨 다음 프로젝트/솔루션을 클릭합니다.
프로젝트 열기 대화 상자에서 TypeEquivalenceInterface 프로젝트를 마우스 오른쪽 단추로 클릭한 다음 속성을 클릭합니다.응용 프로그램 탭을 클릭합니다.어셈블리 정보 단추를 클릭합니다.어셈블리 버전 및 파일 버전 값을 2.0.0.0으로 변경합니다.
ISampleInterface.vb 또는 ISampleInterface.cs 파일을 엽니다.ISampleInterface 인터페이스에 다음 코드를 추가합니다.
Function GetDate() As Date
DateTime GetDate();
파일을 저장합니다.
프로젝트를 저장합니다.
TypeEquivalenceInterface 프로젝트를 마우스 오른쪽 단추로 클릭하고 빌드를 클릭합니다.클래스 라이브러리 .dll 파일의 새 버전이 컴파일된 다음 지정된 빌드 출력 경로(예: C:\TypeEquivalenceSample)에 저장됩니다.
런타임 클래스 수정
런타임 클래스를 수정하려면
Visual Studio의 파일 메뉴에서 열기를 가리킨 다음 프로젝트/솔루션을 클릭합니다.
프로젝트 열기 대화 상자에서 TypeEquivalenceRuntime 프로젝트를 마우스 오른쪽 단추로 클릭하고 속성을 클릭합니다.응용 프로그램 탭을 클릭합니다.어셈블리 정보 단추를 클릭합니다.어셈블리 버전 및 파일 버전 값을 2.0.0.0으로 변경합니다.
SampleClass.vb 또는 SampleClass.cs 파일을 엽니다.SampleClass 클래스에 다음 코드를 추가합니다.
Public Function GetDate() As DateTime Implements ISampleInterface.GetDate Return Now End Function
public DateTime GetDate() { return DateTime.Now; }
파일을 저장합니다.
프로젝트를 저장합니다.
TypeEquivalenceRuntime 프로젝트를 마우스 오른쪽 단추로 클릭하고 빌드를 클릭합니다.클래스 라이브러리 .dll 파일의 업데이트된 버전이 컴파일된 다음 이전에 지정된 빌드 출력 경로(예: C:\TypeEquivalenceSample)에 저장됩니다.
출력 경로 폴더 (예: C:\TypeEquivalenceSample) 파일 탐색기를 엽니다.TypeEquivalenceClient.exe를 두 번 클릭하여 프로그램을 실행합니다.프로그램이 다시 컴파일되지 않고도 TypeEquivalenceRuntime 어셈블리의 새 버전을 반영합니다.