Posts tagged ‘plugin’

Wtyczki do programów w .NET

2010-07-18 12:01

Rozszerzalność od dawna jest w modzie: praktycznie żadna poważniejsza aplikacja nie obywa się bez jakiegoś systemu pluginów, czyli “wtyczek” zwiększających jej funkcjonalność. Niektóre robią to przy okazji (acz ze słusznych powodów), inne czynią z elastyczności i rozszerzalności swój główny oręż (patrz np. uniwersalne komunikatory w typie Mirandy). Wszystko to kojarzy się trochę linuksiarsko, jednakże obecnie także wiele programów stricte pod Windows zachęca (a przynajmniej umożliwia) swoich użytkownika do zakasania rękawów i zakodowania im nowych funkcji.
Dotyczy to także aplikacji na platformę .NET. Co więcej, sama jej natura ułatwia budowanie programów wspierających koncepcję rozszerzalności. Rzecz opiera się na pojęciu assembly, czyli czegoś w rodzaju pakietu (javowe skojarzenia wskazane) zawierającego kod, a więc klasy. Ze względu na to, że .NET Framework zawiera wbudowany kompilator, jest zupełnie możliwe, by nasz program udostępniał całe środowisko do pisania do niego pluginów, a następnie przerabiania ich na kod wykonywalny i podłączania ich do aplikacji. Nie twierdzę, że znam program, który rzeczywiście tak robi, ale przynajmniej w teorii jest to możliwe :)

Powszechniejsze wydaje mi się prostsze podejście, w którym assembly dostarcza się w postaci skompilowanej. Zazwyczaj jest to biblioteka .NET-owych, zapisana jako plik .dll, niemający przy tym zbyt wiele wspólnego z natywnymi czy COM-owymi DLL-ami. Wczytanie go jest bardzo proste, gdy wykorzystujemy do tego klasę System.Reflection.Assembly:

  1. Assembly assembly = Assembly.LoadFrom("ścieżka\do\pliku");

Wskazana jest tutaj ostrożność np. w postaci zapewnienia, że każde assembly ładujemy tylko raz. Najlepiej jest wyznaczyć osobny podkatalog na wtyczki do naszego programu i ładować je jednokrotnie, zapewne podczas uruchamiania samej aplikacji.

Gdy mamy już gotowy obiekt klasy Assembly (niezależnie od tego, czy skompilowaliśmy go sami czy wczytaliśmy go z gotowej binarki tak, jak powyżej), chcielibyśmy pewnie jakoś wykorzystać zawarty w nim kod. Są nim oczywiście jakieś klasy, które możemy pobrać metodą GetExportedTypes. Zwróci nam ona metody tablicę obiektów Type, czyli znanej zapewne metaklasy należącej do .NET-owego systemu refleksji. Z nimi zaś zrobić możemy… no, prawie wszystko :) Do interesujących w kontekście pluginów czynności należy przede wszystkim sprawdzenie, czy dana klasa implementuje jakiś ustalony przez nas interfejs “wtyczkowy”, a następnie utworzenie jej obiektu:

  1. List<IPlugin> plugins = new List<IPlugin>();
  2. foreach (Type type in assembly.GetExportedTypes())
  3.     if (type.IsClass && !type.IsAbstract
  4.         && type.GetInterface(typeof(IPlugin).FullName) != null)
  5.     {
  6.         plugins.Add ((IPlugin)Activator.CreateInstance(type));
  7.     }

Takie beztroskie, dynamiczne tworzenie obiektów z binarnego kodu wczytanego już w trakcie działania programu jest jak najbardziej możliwe i, jak widać wyżej, całkiem proste – stosujemy do tego metodę CreateInstance klasy o wdzięcznej nazwie Activator. Wymogiem jest obecność w klasie wtyczki odpowiedniego konstruktora. W powyższym kodzie zakładamy na przykład najprostszy przypadek, iż dostępna jest jego wersja bezparametrowa.

To w sumie wszystko, jeśli chodzi o wczytywanie. To, w jaki sposób plugin może rozszerzać możliwości naszej aplikacji, zależy głównie od zawartości interfejsu, który nazwałem tutaj umownie IPlugin. Projektując go, powinno się zadbać o jego elastyczność i prostotę, a także wziąć pod uwagę chociażby kwestie bezpieczeństwa.

Tags: , , , ,
Author: Xion, posted under Programming » 2 comments
 


© 2017 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.