Delphi Can

Orjinalini görmek için tıklayınız: Sınıfın Private Alanlarına Erişim
Şu anda (Arşiv) modunu görüntülemektesiniz. Orjinal Sürümü Görüntüle internal link
unit MyClass;

interface

uses Dialogs,
 SysUtils;

type
 TMyClass = class
 private
   FieldA: Integer;
   FieldB: string;
 public
   constructor Create();
   procedure Test;
 end;

implementation

{ TMyClass }
constructor TMyClass.Create();
begin
 inherited;
 FieldA := 123;
 FieldB := 'TEST';
end;

procedure TMyClass.Test;
begin
 ShowMessage(IntToStr(FieldA));
 ShowMessage(FieldB);
end;

end.

Yukarıdaki Uniti projeye ekledikten sonra, TMyClass sınıfından bir nesne oluşturup, private bölümde bulunan FieldA ve FieldB alanlarına erişerek değerlerinin değiştirilmesi istenmektedir.

Kısıtlamalar:
  1. MyClass unit'inde ve TMyClass sınıfında herhangi bir kod değişikliği yapmak yasak.
  2. TMyClass sınıfından bir alt sınıf (sub class) oluşturmak ve kullanmak yasak.
  3. Class helper vs kullanmak yasak.
Test methodunu çağırdığımızda 123 ve TEST değerleri yerine başka değerler görmemiz gerekiyor.
var
 MyObject: TMyClass;
begin
 MyObject := TMyClass.Create;
 {
   sihirli kodlar buraya yazılacak
 }
 MyObject.Test;
 MyObject.Free;
end;


Kolay gelsin.
var
MyObject: TMyClass;
begin
MyObject := TMyClass.Create;                                //MyObject  nesnesi sınıf elemenlarının adreslerinin tutulduğu adresi tutuyor.
integer(pointer(nativeint((@MyObject)^)+4)^):=65;
//önce MyObject 'in adresine (@),ardından elemanların adreslerinin tutulduğu adrese(^),sonra 1.elemanın adresine(+4) ve nihayet elemanın kendisinine(^) ulaşıyoruz.
string(pointer(nativeint((@MyObject)^)+8)^):='Özel Alan Değişti.';
//önce MyObject 'in adresine (@),ardından elemanların adreslerinin tutulduğu adrese(^),sonra 2.elemanın adresine(+8) ve nihayet elemanın kendisinine(^) ulaşıyoruz.
//Not: Burada elemanın boyutunun bir önemi yok,adresler tutulduğu için 4'er bayt ilerlemek eleman adreslerini dolaşmak anlamına geliyor;çünkü adresler 4 byte değerindedir.
MyObject.Test;
MyObject.Free;
end;
type

   TMyClassHook = class(TMYClass);

.

.

.

procedure TForm1.Button1Click(Sender: TObject);
var
 a : TMyClass;
begin
 a := TMyClass.Create();
 TMyClassHook(a).FieldA := 1234;
 TMyClassHook(a).FieldB := 'asd';

 Memo1.Lines.Add(a.FieldB);
 Memo1.Lines.Add(IntToStr(a.FieldA));
end;
var
MyObject : TMyClass;
AValue   : TValue;
begin
MyObject := TMyClass.Create;
AValue := TValue.FromVariant(666);
TRttiContext.Create.GetType(TMyClass).GetField('FieldA').SetValue(MyObject, AValue);
AValue := TValue.FromVariant('DelphiCan');
TRttiContext.Create.GetType(TMyClass).GetField('FieldB').SetValue(MyObject, AValue);
MyObject.Test;
MyObject.Free;
Hakan Bey Yazdığım 2. madde bulunan sub class kullanım kısıtlamasını gözardı etmişsiniz.  Smile 
RTTI kullanımını kısıtlamak aklıma gelmediği için Ali Bey'in cevabı da kabul edilebilir. 
Savaş hocam'ın açıklamaları muazzam. Ben de açık halini paylaşayım.
var
 MyObject: TMyClass;
 P: PByte;
begin
 MyObject := TMyClass.Create;

 P := PByte(MyObject);
 Inc(P, SizeOf(Pointer));
 PINT(P)^ := 321;

 Inc(P, SizeOf(Pointer));
 PString(P)^ := 'XXXX';

 MyObject.Test;
 MyObject.Free;
end;
Zaman ayırıp cevap yazan arkadaşlara teşekkür ederim.
Cevap veren tüm arkadaşların ellerine sağlık. Aynı zamanda bu tarz konuları açan ve destekleyen ismail kardeşime de teşekkür ediyorum.
Internette dolaşırken tesadüfen gördüğüm bir kod içerisinde tam da bu soruya uygun bir cevap buldum Smile

Yeni bir sınıf tanımlıyoruz ve bu sefer ulaşmak istediğimiz değerleri public tanımlıyoruz:
TMyClassAccessor = class
public
   FieldA: integer;
   FieldB: string;
end;

Kullanımı:

var
  MyObject: TMyClass;
begin
  MyObject := TMyClass.Create;
  TMyClassAccessor(MyObject).FieldA := 321;
  TMyClassAccessor(MyObject).FieldB := 'TSET';
  MyObject.Test;
  MyObject.Free;
end;