Rtti Gevşek Unitler :)

Yazdığınız makaleleri ve üyelerimizin işine yarayacağını düşündüğünüz kodlarınızı gönderebilirsiniz. Bu foruma soru sormayın!
Cevapla
ismailkocacan
Üye
Mesajlar: 88
Kayıt: 25 Eyl 2011 06:11
Konum: İstanbul
İletişim:

Rtti Gevşek Unitler :)

Mesaj gönderen ismailkocacan »

Bir projedeki unit'lerin uses bloglarına baktığımızda bir sürü unit ismi görürüz.

Bunların bir çoğu da projeye bizim eklediğimiz unit dosyalarıdır.

Ve hepsi birbirine bağlıdır.Bu bağımlığı en aza indirmenin yollarından birisi de ,reflection kullanmaktır. 8)

Aşağıda yazacağım rttiFormActivator methodu ile bir "unitismi.formsınıfadı" vererek formu oluşturmak için kullanabiliriz.

Bu method kullanıma göre özelleştirebilir.

Unit1.pas

Kod: Tümünü seç

function  rttiFormActivator(typeQualifiedName : string; isModal:Boolean=false) : TValue;
var
 context      : TRttiContext;
 rttTyp       : TRttiType;
 instanceType : TRttiInstanceType;
 instance     : TValue;
begin

 try
   context   := TRttiContext.Create();
   rttTyp    := context.FindType(typeQualifiedName);

   instanceType := rttTyp.AsInstance;
   instance     := instanceType.GetMethod('Create').Invoke(instanceType.MetaclassType,[nil]) ;

   Result := instance;

   case isModal of
      true  :   instanceType.GetMethod('ShowModal').Invoke(instance,[]);
      false :   instanceType.GetMethod('Show').Invoke(instance,[]);
   end;

 except on E: Exception do
   raise Exception.Create(typeQualifiedName+ ' Tipi register edilmemiş !');
 end;

end;
Unit1.pas dosyanın uses bloğuna kullanmak istediğimiz herhangi bir unit içersindeki formun unitini tanımlamadan direk aşağıdaki kullanılabilecektir.

Kod: Tümünü seç

procedure TForm1.btnShowForm2Click(Sender: TObject);
begin
  rttiFormActivator('Unit2.TForm2',true);
end;

Kod: Tümünü seç

procedure TForm1.btnShowForm3Click(Sender: TObject);
begin
  rttiFormActivator('Unit3.TForm3');
end;
unit1.pas'ın uses bloğuna unit2,unit3 eklemeyerek,bu unitlere bağlı olmasını engellemiş ve dinamik bir kullanım elde etmiş olduk.

Yanlız şöyle önemli bir durum var.
Kullanacağınız sınıflarını register etmediğiniz zaman rtti amca findType methodu ile ilgili verdiğiniz tipi bulamıyor.

o yüzden sınıfları bulunduğu unit içinde register ederek,findType methodu ile bulmasını sağlayabiliriz.

Kod: Tümünü seç

initialization
 RegisterClass(TForm2);

finalization
 UnRegisterClass(TForm2);
iyi çalışmalar.
Dosya ekleri
Rtti-Loose-Coupling -Unit.rar
Delphi 2010 Project
(5.34 KiB) 185 kere indirildi
Kullanıcı avatarı
sadettinpolat
Moderator
Mesajlar: 2131
Kayıt: 07 Ara 2003 02:51
Konum: Ankara
İletişim:

Re: Rtti Gevşek Unitler :)

Mesaj gönderen sadettinpolat »

Create metodunu cagirdigimiz da formun onCreate metodu tetikleniyor mu ?
"Sevmek, ne zaman vazgececegini bilmektir." dedi, bana.

---
http://sadettinpolat.blogspot.com/
Kullanıcı avatarı
SimaWB
Üye
Mesajlar: 1316
Kayıt: 07 May 2009 10:42
Konum: İstanbul
İletişim:

Re: Rtti Gevşek Unitler :)

Mesaj gönderen SimaWB »

RegisterClass kullanacaksak bunlara gerek yok sanırım. Eğer

Kod: Tümünü seç

RegisterClass(TForm2);
yaptıysak:

Kod: Tümünü seç

BirForm := TFormClass(FindClass('TForm2')).Create(Application);
BirForm.Show; //yada BirForm.ShowModal
şeklinde formu oluşturabiliriz.
There's no place like 127.0.0.1
ismailkocacan
Üye
Mesajlar: 88
Kayıt: 25 Eyl 2011 06:11
Konum: İstanbul
İletişim:

Re: Rtti Gevşek Unitler :)

Mesaj gönderen ismailkocacan »

sadettinpolat yazdı:Create metodunu cagirdigimiz da formun onCreate metodu tetikleniyor mu ?
evet tetikleniyor.
ismailkocacan
Üye
Mesajlar: 88
Kayıt: 25 Eyl 2011 06:11
Konum: İstanbul
İletişim:

Re: Rtti Gevşek Unitler :)

Mesaj gönderen ismailkocacan »

SimaWB yazdı:RegisterClass kullanacaksak bunlara gerek yok sanırım. Eğer

Kod: Tümünü seç

RegisterClass(TForm2);
yaptıysak:

Kod: Tümünü seç

BirForm := TFormClass(FindClass('TForm2')).Create(Application);
BirForm.Show; //yada BirForm.ShowModal
şeklinde formu oluşturabiliriz.
Bu bağımlığı en aza indirmenin yollarından birisi de ,reflection kullanmaktır.
diğer atraksiyonları reflection(rtti) olmadan yapmak,çok fazla takla atmak gerektirir diye düşünüyorum. :roll:

Şimdilik sadece sınıfı tipini bulduk ve o sınıftan nesne oluşturup,nesnenin "Show" veya "ShowModal" methodlarını çağırdık.
Çünkü bu show ve showmodal methodları TForm sınıfda mevcuttu.
sizin verdiğiniz örnekte birForm.show veya showModal ile bu işin yapılabileceğini ve gerek kalmadığını gördük.


Yukarıda rttiFormActivator methodu ile, bir sınıfın isminden nesne oluşturup,show veya showmodal methodlarını çağırdık.
Bu arada şimdi farkettim yukarıdaki rttiFormActivator methodunda bir bug var :) Biraz beyin fırtanası yapalım :mrgreen:

rttiFormActivator methodu içersinde, "typeQualifiedName" parametresi ile, oluşturmak istediğim nesnenin unitadi.sınıfadı şeklinde verdikten sonra,constructor methodunu çağıryor ve bir nesne oluşturuyorum.

Daha sonra bu nesnenin show veya ShowModal methodlarını çağırarak gösterilmesini sağlıyorum :!:


Peki !
Ya şöyle bir şey yapmak istersek ;


Misal yeni TForm2 aşağıdaki gibi oldu.Yeni bir property ve yeni bir method ekledi.

Kod: Tümünü seç

unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type

  TMyObject = class(TObject)

  end;

  TForm2 = class(TForm)
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
    faktif: Boolean;
  public
    { Public declarations }
    property aktif: Boolean read faktif write faktif;
    procedure kaydet();
  end;


implementation

{$R *.dfm}

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

procedure TForm2.kaydet;
begin
  ShowMessage('kaydettim hacı');
end;

initialization
  RegisterClass(TForm2);

finalization
  UnRegisterClass(TForm2);

end.


TForm2 sınıftan yeni bir nesne oluşturduktan sonra ;
nesne'nin "aktif" property'sine true değeri aktarıp,
nesne kaydet methodunu çağırıp sonra da show veya showmodal le formu göstermek istiyoruz.
Unit2 yi,işlemleri yapmak istediğimiz unit'in uses bloğunda tanımladan nasıl yaparsınız ?


rttiFormActivator methodundaki bug'ı bulana benden çay :mrgreen:
Kullanıcı avatarı
SimaWB
Üye
Mesajlar: 1316
Kayıt: 07 May 2009 10:42
Konum: İstanbul
İletişim:

Re: Rtti Gevşek Unitler :)

Mesaj gönderen SimaWB »

Bu yararlı bilgiler için emeğinize sağlık...

AsInstance kullanmadan önce, yani TRttiType'ı TRttiInstanceType'a cast etmeden önce kontrol etmek iyi olabilir:

Kod: Tümünü seç

if rttTyp.IsInstance then
  instanceType := rttTyp.AsInstance;
Ayrıca GetMethod ile çağrılan methodların varlığı da kontrol edilmeli (if Assigned(...))
Sınıfın Show yada ShowModal özelliği/fonksiyonu yoksa hata verecektir.
There's no place like 127.0.0.1
ismailkocacan
Üye
Mesajlar: 88
Kayıt: 25 Eyl 2011 06:11
Konum: İstanbul
İletişim:

Re: Rtti Gevşek Unitler :)

Mesaj gönderen ismailkocacan »

SimaWB yazdı:Bu yararlı bilgiler için emeğinize sağlık...

AsInstance kullanmadan önce, yani TRttiType'ı TRttiInstanceType'a cast etmeden önce kontrol etmek iyi olabilir:

Kod: Tümünü seç

if rType.IsInstance then
  instanceType := rType.AsInstance;
Ayrıca GetMethod ile çağrılan methodların varlığı da kontrol edilmeli (if Assigned(...))
Sınıfın Show yada ShowModal özelliği/fonksiyonu yoksa hata verecektir.
Yaptığınız tespit doğrudur :bravo:
Size bir çay borcum olsun :D

Aslında bu tip kod kataları çok iyi oluyor.Nitekim ben öğrendiğimi paylaşmak istedim.Ama başka bir hatamın olduğunu öğrendim.
Kullanıcı avatarı
SimaWB
Üye
Mesajlar: 1316
Kayıt: 07 May 2009 10:42
Konum: İstanbul
İletişim:

Re: Rtti Gevşek Unitler :)

Mesaj gönderen SimaWB »

ismailkocacan yazdı: Size bir çay borcum olsun :D
12 Eylül'de İstanbul'daki Delphi lansmanına katılıyorsanız orada çay ısmarlayabilirsiniz :)
There's no place like 127.0.0.1
Cevapla