[MEF] 5. Catalog 사용

Managed Extensibility Framework 2009. 4. 9. 21:31 Posted by POWERUMC
Catalog
 
Catalog 는 동적으로 Composable Part 를 찾아 Container 에 등록합니다. Composable Part 는 ExportAttribute 으로 Contract 를 선언할 수 있는데 개별적으로 일일이 Composable Part 를 등록하는 것은 너무나 큰 반복 작업이 될 수 있지만, MEF 의 Catalog 로 쉽게 자동적으로 등록을 할 수 있습니다.
 
Catalog 를 사용하지 않는 Composable Part 의 등록는 매우 고단한 작업입니다. 아래의 예제 소스 코드는 수동으로 Composable Part 를 등록하는 방법입니다.
 
 
예제에서는 단지 하나의 Export 를 등록하였지만 실제로 이러한 Composable Part 는 수십에서 수백개를 넘을 수 도 있습니다. 많은 Composable Part 를 동적이고 또는 자동적으로 등록해 주기 위해서 Catalog 를 사용하면 쉽게 해결할 수 있습니다.
 
 
이 외에도 Composable Part 를 Catalog 에 등록하는 여러 가지 방법이 있습니다. 아래는 MEF 에서 지원하는 Catalog 입니다.
 
 
Assembly Catalog
 
Assembly Catalog 는 닷넷 어셈블리를 Catalog 로 사용할 수 있습니다.
 
public AssemblyCatalog(string codeBase)
public AssemblyCatalog(Assembly assembly)
 
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
 
AssemblyCatalog 의 시그너처(Signature) 에서 보듯이 CodeBase 로 Catalog 를 사용할 수 있지만, 실버라이트에서는 CodeBase 를 지원하지 않으므로 실버라이트에서는 CodeBase 로 AssemblyCatalog 를 사용할 수 없습니다.
 
 
Directory Catalog
 
Directory Catalog 를 사용하면 특정 폴더의 어셈블리를 모두 검색하여 Composable Part 를 사용할 수 있습니다.
 
public DirectoryCatalog(string path)
public DirectoryCatalog(string path, string searchPattern)
 
Directory Catalog 는 내부적으로 System.IO 의 Directory.GetFiles() 메서드를 사용하여 지정한 폴더의 모든 어셈블리를 검색하도록 하여 Composable Part 를 가져오도록 합니다.
 
var catalog = new DirectoryCatalog("Addins");
 
기본적으로 *.DLL 확장자의 어셈블리만 검색하도록 설정되어있고, 어셈블리 파일의 검색 패턴을 지정하여 검색할 수 있습니다.
 
var catalog = new DirectoryCatalog("Addins", "*.exe");
 
아마 MEF 의 예제중에 XFileExplorer 처럼 특정 폴더에 어셈블리를 복사해 넣으면 자동으로 Composable Part 가 로드되는 예제가 있는데, 이것은 DirectoryCatalog 가 자동으로 처리해 주는 것이 아니라 FileSystemWatcher 클래스를 이용하여 직접 구현해야 합니다.
 
FileSystemWatcher 로 파일의 변경이 감지되면 DirectoryCatalog 의 Refresh() 메서드를 이용하여 폴더를 재검색 또는 새로고침을 할 수 있습니다.
 
 
Aggregation Catalog
 
Aggregation Catalog 는 복합적인 Catalog 를 사용할 수 있도록 합니다. 만약 Assembly Catalog 와 Directory Catalog 등을 동시에 사용하여 Composable Part 를 가져오도록 하려면 Aggregation Catalog 를 사용하면 됩니다.
 
public AggregateCatalog(params ComposablePartCatalog[] catalogs)
 
Aggregation Catalog 의 생성자는 params 로 인자를 받을 수 있습니다.
 
var catalog = new AggregateCatalog(   new AssemblyCatalog(Assembly.GetExecutingAssembly()),
                                                                            new DirectoryCatalog("."));
 
 
Type Catalog
 
Type Catalog 는 Composable Part 를 Type 으로 개별적으로 사용하도록 합니다. 가장 단순하고 무식(?)한 방법일 수도 있지만 세세한 제어가 필요할 때 사용 가능한 Catalog 일 것 같습니다.
 
public TypeCatalog(params Type[] types)
public TypeCatalog(IEnumerable<Type> types)
 
var catalog = new TypeCatalog(typeof(EMailMessageSender), typeof(PhoneMessageSender));
 
 
Using catalog with a Container
 
이제 Catalog 를 Composable Container 에서 Composition 하도록 넘겨주는 일만 남았습니다.
 
public CompositionContainer()
public CompositionContainer(params ExportProvider[] providers)
public CompositionContainer(ComposablePartCatalog catalog, params ExportProvider[] providers)
 
var container = new CompositionContainer(catalog);
 

'Managed Extensibility Framework' 카테고리의 다른 글

[MEF] 7. Exports and Metadata  (0) 2009.04.16
[MEF] 6. Lazy Exports  (0) 2009.04.13
[MEF] 4. Import 선언  (0) 2009.04.07
[MEF] 3. Export 선언  (0) 2009.03.29
[MEF] 2. Parts 와 Contracts 선언  (0) 2009.03.22

WPF 4의 향상된 기능과 Windows 7 지원

WPF 2009. 4. 9. 02:33 Posted by 알 수 없는 사용자

WPF가 발표된지도 많은 시간이 흘렀지만 아직 WPF를 사용한 어플리케이션이 많이 나오지 않는 것이 현실입니다. 앞으로 Visual Studio 2010과 .NET Framework 4.0이 발표되면 WPF 역시 4.0으로 버전업이 되는데 이제 현실적으로 많이 사용 될 수 있을 정도로 많은 발전이 있습니다. 

알려진 바와 같이 Visual Studio 2010 IDE에서도 WPF가 사용될 정도로 성능이나 여러 면에서 많은 발전이 있습니다.


이번 MIX09 행사의 WPF4 소개 세션 자료를 보면 매우 많은 요소가 향상된 것을 볼 수 있습니다.

이 중에서 가장 눈에 띄는 것은 아무래도 Multi-Touch 지원이 되겠는데 이 것은 Windows 7에서 기본으로 Multi-Touch를 지원 하게 됨으로써 WPF에서도 이를 활용한 어플리케이션 개발을 할 수 있게 되었습니다.

 

이 외에도 중요한 몇 가지를 보면 Windows 7에서 새롭게 바뀐 Taskbar와 Office 2007에서 사용된 Ribbon UI를 기본으로 지원하게 되고 다양한 새로운 컨트롤과 .NET Framework 4에서 향상된 언어 기능들도 추가 되었습니다. 

이런 향상된 기능들을 지원하기 위해 WPF에서 어떤 변화가 있는지 자세히 알아보도록 하겠습니다. 


Multi-Touch in WPF

 

UIElement 변화 

WPF 개발을 해보신 분들은 UIElement 클래스에 대해 잘 알고 계실겁니다. UIElement 클래스는 WPF의 가장 기본이 되는 최상위 기본 클래스인데 멀티터치 지원을 위해서 내부적으로 몇 가지 변화가 생겼습니다. 우선 기존의 이벤트로는 멀티 터치를 지원 할 수 없기 때문에 멀티터치와 제스처 인식을 위한 이벤트가 추가 되었습니다.

 

멀티터치 지원 컨트롤 

ScrollViewer 컨트롤의 경우 제스처 인식을 하도록 업데이트 되었고 다른 기본 컨트롤들도 멀티터치 지원을 위해 업데이트 되었습니다. 동시에 하나 이상의 포인트를 인식하기 위해 멀티캡쳐 기능도 지원하게 되었습니다. 이 외에도 ScatterView 같은 멀티터치를 위한 새로운 컨트롤도 추가 되었습니다.

 

Surface SDK 2.0 호환 

Sufrace SDK 2.0의 호환으로 Surface 컴퓨터의 멀티터치 어플리케이션 개발을 쉽게 할 수 있습니다.

WPF Taskbar Integration

 

Windows 7에서는 기존보다 향상된 태스크바를 제공하는데 이를 지원하기 위한 내용이 포함 되었습니다.

 

Windows API Code Pack for .NET

Windows 7에서 추가되거나 향상된 API들을 사용하기 위해서는 C, C++, COM API 같은 네이티브 코드를 사용해야 합니다. 그러나 C# 등의 매니지드 코드를 사용하는 닷넷 개발자에게는 이것이 어렵게 느껴 질 수 있습니다. 그렇다고 새로운 멋진 기능들을 포기하자니 아쉽고 네이티브 코드를 사용하자니 불편하고 좀 더 편하게 할 수 있는 방법은 없을까요?  

이러한 것을 해결 하기 위해 Microsoft에서는  Windows Vista Bridge project를 만들었는데 이것을 사용하면 매니지드 코드 개발자가 Windows API를 쉽게 사용 할 수 있습니다. 현재 최신 버전은 1.4인데 Restart and Recovery, Search, Power Awareness and other Shell integrations 같은 Windows Vista의 많은 유용한 기능들을 포함 하고 있습니다. 그러나 현재 버전은 Windows7의 기능들을 포함하고 있지는 않습니다. 

Windows7은 현재 베타가 공개되었고 조만간 RC버전이 나온다고 하는데 Windows 7의 API 지원을 위한  Windows API Code Pack for the .NET Library(이것은 Windows Vista Bridge의 새 이름)도 함께 개발중으로 같이 배포 될 예정입니다. 

현재는 Windows Vista Bridge에서 약간 수정된 버전으로 Windows 7 API 일부를 지원하는 샘플 라이브러리가 있는데 이것은 다음에 자세히 알아 보도록 하겠습니다. 

 

WPF Ribbon

Visual Studio 2008에서는 MFC를 사용하여 Ribbon UI를 개발 할 수 있습니다. 그런데 WPF에서는 기본적으로는 Ribbon UI를 지원하지 못하고 WPF Toolkit을 통해서 따로 지원하고 있는데 WPF 4에서는 Ribbon UI를 기본적으로 지원하게 됩니다. 

 

WPF Controls

윈도우 프로젝트에서 많이 쓰이는 컨트롤 중 하나가 데이터 그리드나 달력 컨트롤 등이 있는데 WPF 기본 컨트롤에서는 지원하지 않고 WPF Toolkit으로 따로 지원하고 있습니다. Ribbon과 마찬가지로 이것도 역시 WPF 4에서는 기본으로 포함되게 됩니다. 이 외에도 Silverlight에서 지원하고 있는 차트 컨트롤 등도 WPF에서 역시 지원하게 됩니다.


 

대표적으로 살펴 본 것 외에도 많은 변화가 있고 향상 되었습니다. 다음 포스팅 부터는 이번에 살펴본 것을 중심으로 실제로 어떻게 사용하고 구현하게 되는지 자세히 알아보도록 하겠습니다. 

앞으로 Visual Studio 2010과 WPF 4의 향상된 기능 많이 기대 해주세요 :)

'WPF' 카테고리의 다른 글

WPF 리본 컨트롤 RTW 출시  (4) 2010.08.05
WPF Features Preview (3) - Styling the DataGrid  (1) 2009.04.23
WPF Features Preview (2) – DatePicker  (1) 2009.04.22
WPF Features Preview (1) – DataGrid  (1) 2009.04.17

Welcome to F#(2) - 두번째 만남.

F# 2009. 4. 8. 23:40 Posted by 알 수 없는 사용자

-애프터
첫번째 만남이 끝난뒤에, 어떻게 애프터를 이어나가야 할지 무처이나 고민했습니다. 첫만남이야 가볍게 서로의 얼굴도 보고, 성격도 맛보는 정도에서 끝난다지만 애프터에서는 서로에 대해서 천천히 자세히 알아가야 할텐데, 갑자기 참여중인 프로젝트의 상황이 악화되서 시간이 잘 나지 않고, 이해부족과 실력부족이 겹쳐서 어떻게 글을 계속 써나가야할지 고민이 많았습니다. 그러다가 직장동료에게 물어봤습니다.

"만약에 튜토리얼을 쓴다면, 어떻게 쓰는게 좋을까?"
"글쎄, 나는 그런게 좋던데. 왜 작은 예제에서 시작해서 하나씩 추가되어 가면서 설명해주는 그런거 있잖아."

이거다 싶었습니다. 그래서 제 내공이 받쳐줄지는 모르겠지만, 최대한 예제를 통해서 F#과의 애프터를 진행해볼까 합니다. 언제나 그렇듯이 제 글에 어색하거나 잘못된 내용이 있을수 있으니 언제나 따뜻한 피드백으로 격려해주시기 바랍니다.(말씀드렸듯이 차가운 피드백은 바로 반사-_-) 그럼 일단 애프터 장소로 가서 F#을 좀 더 만나보도록 하죠~.

-F#에서는 타입을 안쓰는거 같더라?
일단 F#에서 타입을 결정하는데 쓰이는 타입유추(Type Inference)에 대해서 알아보겠습니다. 타입유추는 F#에서만 쓰이는 개념은 아닙니다만, 저 같이 함수형언어에 친숙하지 않은 경우에는 생소함을 느끼게 됩니다. 우선 아래와 같은 예제를 작성해서 아래 두줄을 드래그 해서 F# Interactive로 보내보죠. F# Interactive를 띄우는 방법과 F# Interactive로 보내는 방법은 잊지 않으셨죠? 잊으셨다면, 이전 포스트를 참조해주세요~.

#light

let count = 1
printfn "%d" count


실행결과에 대해서 이야기 하기전에 #light에 대한 설명을 조금 드리자면, 지난 포스트에서 말씀드린 것 같이 이 지시어는 F#에서 좀더 간략한 문법을 사용할 수 있도록 해줍니다. 그런데, 이런 키워드를 명시적으로 꼭 선언해야 하는 이유는 다음과 같습니다. F#은 OCaml으로 부터 영감을 받아서 설계되고 핵심적인 부분중에 일부분을 공유하고 있씁니다. 그리고 OCaml의 코드를 컴파일할 수 있는 기능을 갖추고 있는데, 간단한 OCaml코드의 경우는 수정없이 컴파일 가능하게 되어있습니다. 그래서 그 경우를 위해서 #light라고 명시해줘야만 F#의 간단한 문법이 적용되는 것입니다.

그러면, 다시 소스코드로 넘어가서 그 소스의 결과는 아래와 같습니다.

val count : int
1
 
즉, 한줄씩 평가 돼서 그 결과가 나오는 건데요, 첫번째 줄은 count라는 value를 선언했고 그 타입은 int라는 말입니다. 그리고 그 다음줄은 count의 값을 출력한 결과인거죠. 눈치 빠른 분이라면, 아마 여기서 뭔가를 눈치채셨을 겁니다. 타입을 정해주지 않았는데, count의 타입이 int라는걸 문맥을 통해 유추해냈습니다. 그리고 아래의 printfn의 출력패턴을 보면 "%d", 즉 C와 동일하게 정수형값을 출력하겠다는 말인데요, 앞의 평가식에서 count가 정수형이라는 걸 유추해냈기 때문에 에러없이 1을 출력하고 프로그램을 종료합니다. 이런걸 타입 유추라고 부릅니다.(원문으로는 Type Inference인데, inference에 대한 딱히 다른 용어를 찾지 못해서 일단 유추라고 하겠습니다.-_-)

타입유추는 코드를 분석해서 제약사항들을 모아서 이루어집니다. 여기서 제약사항이란, 매개변수가 가질 수 있는 타입을 명시해줌으로써 제약을 가하는 개념인데요, 문맥에서 타입을 유추할때 +,-,*,/같은 경우는 기본적으로 매개변수를 int타입으로 유추됩니다. 그리고 아래의 예제들을 F# Interative에 평가해보죠.

let printInt x = printfn "%d" x

let printString x = printfn "%s" x

그러면, 아래와 같은 결과가 나오죠.

val printInt : int -> unit

val printString : string -> unit

즉, 문맥상 정수형을 출력하니까 x는 int형이 된거고, 문맥상 스트링을 출력하니깐 x는 스트링으로 유추된 거죠. 그리고 아래의 예제를 더 보시죠.(그리고 참고로 unit은 많은 분들이 기대하시는 것 처럼 unsigned int는 아니구요, 정확하게 같진 않지만 void를 나타내는 F#의 타입입니다.-_-)

let plusplus x = (x + x)
let plusplus2Times (x) = plusplus x + plusplus x
-----결과----
val plusplus : int -> int
val plusplus2Times : int -> int

그리고 아래와 같이 바꿔서 다시 평가해보죠.

let plusplus x = (x + x)
let plusplus2Times (x:float) = plusplus x + plusplus x
-----결과----
val plusplus : float -> float
val plusplus2Times : float -> float

역시 사용되는 문액에 따라 plusplus를 호출하는 plusplus2Times에서 int형 x를 넘겨주면, plusplus의 매개변수도 int타입이 되고, float을 사용하겠다고 타입에 제약을 정해주면(즉, 매개변수 x가 될 수 있는 타입에 명시적으로 제약을 주는 것) 그에 따라서 plusplus에 넘어가는 매개변수와 리턴타입역시 그에 따라 float타입으로 유추되는 것을 볼 수 있죠. 즉, F#에서는 타입을 명시해줄 수도 있지만, 이런 작업을 직접 해주지 않으면 기본적으로는 타입유추를 통해 타입을 알아내고 적용한다는 겁니다.

-타입유추라는거 왠지 불안해보이는데?
이런 생각을 해볼 수 있습니다. '과연 이렇게 컴파일러가 타입을 추측해주는게 무슨 장점이 있는거냐?' 이 포스트에서 관련된 내용을 많이 찾아볼 수 있었습니다. 저자는 타입유추의 광팬이로군요. 언제든지 C#같은 언어에서 제공하는 var타입이나 익명메서드등을 사용해서 자기 대신 컴파일러가 타입에 대한 문제를 다루도록 한답니다. 즉, '타입유추는 타입안정성을 해치지 않고 그저 컴파일러가 대신 타입을 찾을뿐이다', '타입을 일일이 적지 안아도 되니깐 리팩토링시에도 편리하다', '타이핑을 줄일 수 있다'랍니다. 그리고 반론도 만만치 않습니다. 아주 긴 댓글로 서로 의견을 주고 받고 있군요. 즉, 한마디로 좋다 나쁘다를 정할 수 없는 취향의 문제인것 같기도 합니다.(우주 끝날때까지도 결론이 안 날문제들이 바로 취향에 관련된 문제죠-_-)

-F#은 어떤 타입이야?
그리고 타입이야기가 어쩌다 새어나왔으니, 타입을 한번 적어보겠습니다.
 타입  예  설명
 int  int  그냥 32비트 정수입니다.
 type option  int option, option<int>  선언된 타입의 값이 있거나, 혹은 값이 없는 걸 의미하는 None을 가집니다. Optional parameter와 비슷한 개념입니다.
 type list  int list, list<int>  선언된 타입의 immutable한 값들의 linked list입니다. 리스트의 각 값들은 [5;2;88]처럼 같은 타입을 가져야 합니다.
 type1 -> type2  int -> string  함수타입입니다. 즉, type1을 받아서 결과값으로 type2를 리턴한다는 거죠.
 type1 * ... * typeN  int * string  한쌍(a pair), 두쌍 그리고 그 이상의 타입들의 조합이 가능한 튜플타입입니다. (1, "3")같은 경우 말이죠.
 type []  int[]  배열타입이죠. 1차원이고, 고정된 크기의 mutable한 값들의 모음입니다.
 unit  unit  하나의 값을 나타내는 ()을 나타내는데, 명령형 언어의 void와 비슷한 의미입니다.
 'a, 'b  'a, 'b, 'Key, 'Value  제네릭하게 어떤 타입이든지 올 수 있는 변수타입입니다.

Expert F#에 나오는 예제를 마지막으로 보겠습니다.

 String.split [' '] "hello world"

 String.split ['a';'e';'i';'o';'u'] "hello world"

일단 위의 코드를 F# Interactive에 보내서 평가해보면 "The value, constructor, namespace or type 'split' is not defined. A construct with this name was found in FSharp.PowerPack.dll,......"이런 에러가 뜹니다. 즉, String클래스에 split이라는 값이나, 생성자, 네임스페이스 혹은 타입이 존재하지 않는데, FSharp.PowerPack.dll에서 발견이 되었다는 친절한 메세지 입니다. CTP버전으로 오면서 많은 기능이 FSharp.PowerPack.dll로 옮겨졌기 때문입니다. String은 Microsoft.FSharp.Core.String을 참조하는데요 Microsoft.FSharp안에 있는 Core,Collection,Text,String같은 네임스페이스는 String.split이나 open String같이 한 단어로 참조가 가능하고 합니다. 이럴땐, FSharp.PowerPack을 참조추가해줘야겠죠. 참조추가후에 open 지시어를 통해서 해당 네임스페이스의 내용을 알아내야 하는데, F# Code에선 기본적인 Core나, Operators, Collections같은 네임스페이스는 암시적으로 open을 한다고 합니다. 그리고 비주얼 스튜디오가 아닌 F# Interactive에서 참조추가를 하려면, 아래 처럼하면 됩니다.

 > #r "FSharp.PowerPack.dll";;

--> Referenced 'C:\Program Files\FSharp-1.9.6.2\bin\FSharp.PowerPack.dll'


그리고 다시 F# Interactive로 보내서 평가해보면 아래와 같은 결과나 나옵니다.

 val it : string list = ["hello"; "world"]
>
val it : string list = ["h"; "ll"; " w"; "rld"]

이 예제에서 ' ', 'a'는 그냥 문자고, "hello world"같은건 문자열, ['a';'e';'i';'o';'u']는 문자의 리스트, ["hello"; "world"]는 문자열의 리스트라는 걸 알 수 있습니다.

-애프터의 만족도는?
변명이지만, 시간도 조금은 부족했고, 아는것도 부족하다보니 포스트의 내용이 썩 만족스럽지는 못한 것 같습니다. 애프터가 만족스럽지 못하셨다면, 제탓이 가장크겠군요-_-. 그래도 마음에 드신분이 있다면, 몇번 애프터를 더 해보고 손이라도 잡아봐야 겠죠. 다음번엔 이어서 기본적인 타입에 대해서 좀 더 알아보고, .NET공원에서 놀이기구를 몇개 타보는 걸로 해볼 생각입니다. 그리고 이번포스트에서 제대로 조사하지 못한 부분역시 조사해볼 생각입니다. 데이트장소는 고전적이긴 하지만 놀이공원도 괜찮죠. 그럼 도움이 되는 분들이 있길 바라면서 다음 포스트에서 뵙겠습니다.

-참고자료
1. Expert F#, Don Syme, Adam Granicz, Antonio Cisternino, APRESS.
2. http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/spec2.aspx#_Toc207785764
3. http://blogs.msdn.com/jaredpar/archive/2008/09/09/when-to-use-type-inference.aspx