Obiektowość .NET

Adam Boduch

Środowisko .NET Framework jest w pełni obiektowe. Programująć w .NET korzystamy z biblioteki klas FCL (ang. Framework Class Library), które udostępnia nam setki klas, struktur, typów wyliczeniowych, dzięki którym możemy tworzyć profesjonalne aplikacje w systemie Windows [#]_.

Warto wspomnieć o tym jak do tego ustosunkowała się firma Borland, która przystosowała swój produkt do tworzenia aplikacji na platformę .NET. Powiedzieliśmy, że w .NET wszystko jest typem, nawet typy danych takie jak String czy Integer wskazują na typy .NET: System.String oraz System.Int32. Język C# wymusza od nas np. aby w aplikacji znalazła się conajmniej jedna klasa, nie daje nam przy tym możliwości programowania strukturalnego. W Delphi wciąż taka możliwość istnieje. W rzeczywistości jednak, kompilator przekształca nasz iście strukturalny moduł w klasę, która w takiej postaci kompilowana jest do kodu IL.

Spójrzmy na przykładowy, prosty moduł zawierający deklarację oraz definicję funkcji:

unit Boduch.Test;

interface

  function GetName : String;

implementation

function GetName : String;
begin
  Result := 'Boduch.Test';
end;

end.

Moduł nosi nazwę Boduch.Test, zawiera jedną funkcję, niemającą specjalnego znaczenia. Po użyciu takiego modułu w tworzonej aplikacji i skompilowaniu programu kompilator przekształci kod do następującej postaci:

unit Boduch.Units;

interface

type
  Test = class
  public
    class function GetName : String; static; 
  end;

implementation

class function Test.GetName : String;
begin
  Result := 'Boduch.Test';
end;

end.

Oczywiście wszystko dzieje się w sposób niewidoczny dla programisty. Przeprowadźmy pewien test. W tym celu należy utworzyć nowy projekt aplikacji konsolowej dla .NET, dodać do programu moduł Boduch.Test.pas, a jego zawartość doprowadzić do takiej postaci, jaka została zaprezentowana na listingu.

Kolejnym krokiem jest skompilowanie budowanego programu. Jest to prosta aplikacja konsolowa, na dysku taki program zajmuje 18 kB. Można teraz uruchomić deasembler .NET i przeanalizować ten program. Deasembler wyświetli zawartość opisywanego podzespołu, z podziałem na przestrzenie nazw (patrz rysunek).

Deasembler_NET.jpg

Z tego, co można zaobserwować na rysunku, w naszym podzespole znajduje się metoda GetName, której zawartość w formie kodu IL prezentuje się tak:

.method public static string  GetName() cil managed
{
  // Code size       8 (0x8)
  .maxstack  1
  .locals init ([0] string Result)
  IL_0000:  ldstr      "Boduch.Test"
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  ret
} // end of method Test::GetName

Jak widać, kompilator Delphi przekształca kod modułu do klasy. Wspomniałem jednak tylko o tych procedurach i funkcjach modułu, które ulegają konwersji do metod. Tak samo dzieje się ze zmiennymi, znajdującymi się w module. Są one przekształcane do pól klasy i umiejscawiane w sekcji Public:

unit Boduch.Test;

interface

var
  Variable : Integer;

Powyższy kod zostanie przekształcony do:

type
  Test = class
  public
    class Variable : Integer; 
  end;

To samo można powiedzieć o sekcji Initialization, która jest opcjonalna w modułach Delphi. Podczas kompilacji programu jest tworzony konstruktor w klasie i następuje umieszczenie kodu z sekcji Initialization w konstruktorze:

initialization
  Variable := 10;

Powyższy kod jest umiejscawiany w konstruktorze:

class constructor Test.Create; static;
begin
  Variable := 10;
end;

Odkąd moduły mogą posiadać blok begin..end, kod znajdujący się w tej sekcji jest umieszczany w metodzie o nazwie odpowiadającej nazwie modułu:

unit Boduch.Test;

interface

var
  Variable : Integer;

  function GetName : String;

implementation

function GetName : String;
begin
  Result := 'Boduch.Test';
end;

begin
  Variable := 20;
end.

Moduł jest przekształcany do takiej postaci:

unit Boduch.Units;

interface

type
  Test = class
  public
    class Variable : Integer; 
    class function GetName : String; static; 
    class procedure Boduch.Test;
  end;

implementation

class function Test.GetName : String;
begin
  Result := 'Boduch.Test';
end;

class procedure Test.Boduch.Test;
begin
  Variable := 10;
end;

end.

Dociekliwy Czytelnik może także spytać, co się dzieje w sytuacjach, w których zmienne globalne mają nadane wartości już w trakcie pisania programu:

var
  Variable : Integer = 10;

W takim przypadku wartość pola Variable jest nadawana w konstruktorze klasy.

Mam nadzieje, że dzięki temu któtkiemu artykułowi, rozwiano wątpliwości co do pozornej strukturalności języka Delphi .NET.


.. [#] Niestety obsługa .NET na platformie Linux/Unix pozostawia wciąż wiele do życzenia

9 komentarzy

Ja tak na marginesie dodam :
http://blogs.borland.com/chewy/archive/2006/11/21/29604.aspx

Moim zdaniem po tym jak Novel wsparl Mono zaczyna byc ciekawie

Zgadza sie. Ale dlatego .NET jest wlasnie takie fajne, ze mamy mozliwosc wyboru platformy programistycznej :) I wiele osob tworzacych aplikacje pod .NET moze wybierze Delphi, dlatego ze jest przyjazne, latwe w uzyciu i przede wszystkim - znane.

Zgadzam sie z jednym - rozpoczynajac nowy projekt pod .NET nie ma sensu tworzyc go pod VCL.NET raczej. Bo tworzyc aplikacje pod .NET tylko po to aby dzialaly pod .NET a i tak wykorzystujac przy tym jezyk Delphi i VCL? To sie mija z celem chyba. Ale chcac przeniesc aplikacje z Win32 na .NET, VCL.NET moze byc dobrym "przystankiem" ...

Adam: no ok.. kompilacja starych programów.. ale 95% z nich jedzie na VCL, kolejny uważam zły wymysł, VCL.NET bo potem skompilować takie coś przez csc na kompie bez kompilatora borlanda to nici..

Marooned: nie no to jest calkiem sluszne. Gdyby Borland wymusil stosowanie klas, stare kody zrodlowe stracilyby na kompatybilnosci. A teraz wcale nie tak trudno przeniesc swoje aplikacje na .NET.

Coldpeer: Ja tam sie ciesze, fajnie gdyby Mono bylo kompatybilne z .NET. Ale do tej pory jeszcze tego nie zrobili z tego co wiem. No i z jaka wersja .NET Framework bedzie kompatybilny Mono? I z jaka jest teraz? Bo chyba nie 2.0? Albo obsluga C#? Zakladam ze jest to obsluga v. 1

Znów Delphi uczy złych manier, bo 80% programerów będzie myślało, że piszą sobie strukturalnie w .NET ...

Adam: wersja 1.2 MONO będzie podobno kompatybilna z Windows.Forms :)

A robiles cokolwiek na tym?:)

No i? :) Napisalem przeciez ze pozostawia wiele do zyczenia :PP Mono zawsze bedzie do tylu za .NET

[1] Niestety obsługa .NET na platformie Linux/Unix pozostawia wciąż wiele do życzenia
http://www.mono-project.com