pondělí 19. září 2011

Unity vs MEF vs PRISM


Unity, MEF a PRISM jsou kniovny, které řeší závyslosti, modularitu a lehkou rozšiřitelnost vaší aplikace. Podívejme se stručně, jaké jsou v nich rozdíly.


Unity vs MEF
Unity se nejvíce používá k pro pevné statické závislosti a je to více "vnitřní" technologie. Nikdo mimo vyvojáře nic nemusí vědět o vnitřním uspořádaní aplikace.
MEF se používá pro řešení dynamických závislostí, dynamické načítání komponent. Pomocí MEF lze snadno tvořit rozšiřující moduly aplikace.


PRISM 
Je framework využívající Unity nebo MEF, který umožňuje vytvářet modulární aplikace, kdy si aplikace může sama moduly natahovat až ve chvíly kdy je potřebuje. Pomocí RegionManager můžete pohledy z modulů vkládat do hlavního okna (Shell) aplikace. Pro sdílení událostí se využívá EventAggregator a Command. PRISM je možné využít s výhodou u návrhového vzoru ModelView-ViewModel.

Pod čarou:
  • MEFnení IoC (Inversion of Control) kontejnér, ale využívá IoC koncept.
  • Unity je IoC kontejnér.
  • MEF se zaměřuje především na rozšiřitelnost aplikace a na uspořádání pomocí kompozice. Aplikaci skládáme z částí.
  • PRISM je kompletní řešení pro tvorbu uživatelských aplikací.
  • MEF není kompletní řešení pro tvorbu uživatelských aplikací, je to jen knihovna umožňující snadnou rozšiřitelnost aplikace.

pondělí 12. září 2011

DI - depency injection - Unity

Materiál:

http://www.codeproject.com/KB/cs/MEF_UnityInterception.aspx
http://martinfowler.com/articles/injection.html
- Skrýt citovaný text -


2011/9/12 Michal Svoboda
http://weblogs.asp.net/podwysocki/archive/2008/02/26/ioc-and-the-unity-application-block-once-again.aspx
http://entlib.codeplex.com/
http://msdn.microsoft.com/en-us/magazine/cc163739.aspx#S8

Mixed DLL - Kombinované DLL - (.net a nativní)

Před 14 dny jsem dostal úkol, volat funkce a DLL mého kolegy. DLL je napsané v C++ Builderu tedy v nativním běhovém prostředí. Spouštění funkcí z nativního DLL není nic světoborného a .NET na to má sekci zvanou System.Runtime.InteropServices. Rozhodl jsem se napsat tuto glosu, protože občas se mi DLL zavolá v pořádku a občas volání selže. Hledal jsem nejrůznější články na googlu a narazil jsem pouze na tzv. Mixed DLL problém:
http://www.codeguru.com/columns/kate/article.php/c3643

Na MSDN je celý článek o volání native DLL:
http://msdn.microsoft.com/en-us/magazine/cc164123.aspx

Důležitým parametrem pro volání je volací konvence CallingConvention = CallingConvention.Cdecl. Máte na výběr z několika volacích konvencí: Cdecl, StdCall, FastCall, ThisCall a WinApi

Při volání funkcí předáváme parametry a musíme zajistit, aby parametry z .net odpovídali parametrům z nativního světa.

char = System.SByte
int = System.Int32

O předávání dat se stará tzv. Marshaling
Můžeme využít defaultního předávání dat, ale pokud z nějakého důvodu .net typ neodpovídá nativnímu typu mužeme si explicitně říct, jakým způsobem chceme data u konkrétního parametru předat. K tomu slouží: [MarshalAs(UnmanagedType.LPWStr)]jméno_parametru. Toto využijeme zvláště při například u stringů nebo složitějších polí.

Pokud v .net pracujeme se stringem, definujeme jej jako string. V C/C++ je situace poněkud složitější. Můžeme pracovat s C stringem, to je pole znaků char, pak můžeme mít pole unicode znaků wchar_t nebo bstr stringy a podobně. Proto při předávání .NETu musíme explicitně říct, jaký string chceme do nativního prostředí předat.

Příklad: BStr, LPStr, LPWStr,  LPTStr atd.

Příklad volání:
[DllImport("ImportGS.dll", EntryPoint = "_DB_ImportXML", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern int db_ImportXML(string filename, TFileType type, bool full);

Importovanou funkci si můžete pojmenovat libovolným způsobem, ale pak musíte její jméno napsat do Attributu EntryPoint a také musíte dát pozor na volací konvence a '_'. Dáe musíte dát pozor na typy řetězců.

Nyní již umíme zavolat nativní dll, ale podívejme se ješte jak může takové dll zavolat náš .net kód zpět pomocí callbacku.

Callback
V hlavičkovém souboru jsem měl definovaný callback:
typedef void (TNotice)(wchar_t *msg, bool error);
V Céčku je callback reprezentovaný jako ukazatel nafunkci. V .NETu takový callback realizujeme pomocí delegáta:

 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
 public delegate void CallbackDelegate([MarshalAs(UnmanagedType.LPWStr)]StringBuilder msg, bool error);

Explicitně říkám, že jde o UnmanagedFunctionPointer (ukazatel z jiného světa :)) a určím jeho volací konvenci. Pak definuju delegáta tak, aby mu odpovídali parametry s jeho Céčkovským protějškem. A také určím, jak se mají předávat parametry Marshalingem.

Na závěr bych chtěl ještě upozornit na možnost předávat a zpracovávat parametry více způsoby. Vezměme si oblíbený string.

String je možné předávat jako string, StringBuilder a nebo například jako IntPtr, který si přetypujeme až v těle delegáta.

StringBuilder využíváme v případě, že se řetězec předává jako reference a vrátí se mi zpět změněný.

Pokud si předáme string jako IntPtr msg, tak výsledný string získáme voláním:
string msg_decode = System.Runtime.InteropServices.Marshal.PtrToStringUni(msg);