Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2008.04.27;
Скачать: CL | DM;

Вниз

var vs class var   Найти похожие ветки 

 
Pir   (2008-03-18 05:52) [0]

Сори, что пишу сюда, но тут есть шанс, что ответят по-быстрому...

Вопрос такой: пишу класс на дельфях, в нем должна быть одна переменная типа TEvent = procedure (Sender: TBaseObject; Param: Cardinal). Запихиваю ее в private с именем fUniversal и делаю к ней property. Но при работе программы что-то происходит в этом классе и значение Addr(fUniversal) постоянно равно то адресу процедуры, то нулю. При этом если вызывать ее без проверки, она выдает AV. Но все работает, если fUniversal задать как class var. Но нужна не общая переменная. Не подскажете, как быть?

Вот юнит с этим классом:
unit EventManager;

interface

uses BaseObject, Variants;

type
 TEvent = procedure (Sender: TBaseObject; Param: Cardinal);

 TEventProperty = record
   Name: String;
   Event: TEvent;

   Param: Cardinal;

   procedure Call(const Sender: TBaseObject = nil);
 end;

 TEventManager = class(TBaseObject)
 private
   fEvents: Array of TEventProperty;
   fCaseSensetive: Boolean;
   fAutoClean: Boolean;

   class var fUniversal: TEvent;
 protected
   function GetEventIndexByName(Name: String): Integer;
   function GetEventByName(const Name: String): TEvent;
   function GetEventByIndex(const Index: Cardinal): TEvent;
   procedure AddEvent(const Name: String; const Event: TEvent);
   procedure SetEventValueByName(const Name: String; const Event: TEvent);
   procedure SetEventValueByIndex(const Index: Cardinal; const Event: TEvent);
   function GetUniversal: TEvent;
   procedure SetUniversal(const Event: TEvent);
 public
   property Events[const Name: String]: TEvent read GetEventByName write SetEventValueByName; default;
   property Events[const Index: Cardinal]: TEvent read GetEventByIndex write SetEventValueByIndex; default;

   property Universal: TEvent read GetUniversal write SetUniversal;

   procedure Init(const Name: String; const Parent: TBaseObject); override;
   procedure DeInit; override;

   procedure Process; override;

   procedure Clear;

   procedure Clean;

   procedure Call(const Name: String; const Sender: TBaseObject = nil; const Param: Cardinal = 0);

   function Count: Integer;
 published
   property CaseSensetive: Boolean read fCaseSensetive write fCaseSensetive;
   property AutoClean: Boolean read fAutoClean write fAutoClean;
 end;

function CreateEventManager(const Name: String = ""; const Parent: TBaseObject = nil): TEventManager;

implementation

uses SysUtils;

procedure TEventProperty.Call(const Sender: TBaseObject = nil);
begin
 if @Event <> nil then
   Event(Sender, Param);
end;

procedure TEventManager.Init;
begin
 inherited;

 Clear;

 fCaseSensetive := False;
 fAutoClean := True;
 fUniversal := nil;
end;

procedure TEventManager.DeInit;
begin
 Clear;

 inherited;
end;

procedure TEventManager.Process;
begin
 if fAutoClean then
   Clean;
end;

procedure TEventManager.Clear;
begin
 SetLength(fEvents, 0);
end;

function TEventManager.GetEventIndexByName(Name: String): Integer;
var
 i: Integer;
 PropName: String;
begin
 Result := -1;

 if Length(fEvents) = 0 then Exit;

 Name := Trim(Name);
 if not fCaseSensetive then Name := LowerCase(Name);

 for i := 0 to Length(fEvents) - 1 do begin
   PropName := Trim(fEvents[i].Name);

   if not fCaseSensetive then PropName := LowerCase(PropName);

   if Name = PropName then begin
     Result := i;
     Exit;
   end;
 end;
end;

function TEventManager.GetEventByName(const Name: String): TEvent;
var
 Index: Integer;
begin
 Result := nil;

 Index := GetEventIndexByName(Name);

 if Index >= 0 then begin
   Result := fEvents[Index].Event;
 end;
end;

function TEventManager.GetEventByIndex(const Index: Cardinal): TEvent;
begin
 Result := nil;

 if (Index < 0) or (Index >= Length(fEvents)) then Exit;

 Result := fEvents[Index].Event;
end;

procedure TEventManager.AddEvent(const Name: String; const Event: TEvent);
begin
 SetLength(fEvents, Length(fEvents) + 1);
 fEvents[Length(fEvents) - 1].Name := Name;
 fEvents[Length(fEvents) - 1].Event := Event;
end;

procedure TEventManager.SetEventValueByName(const Name: String; const Event: TEvent);
var
 Index: Integer;
begin
 Index := GetEventIndexByName(Name);

 if Index < 0 then begin
   AddEvent(Name, Event);
 end else begin
   fEvents[Index].Name := Name;
   fEvents[Index].Event := Event;
 end;
end;

procedure TEventManager.SetEventValueByIndex(const Index: Cardinal; const Event: TEvent);
var
 OldCount: Integer;
 i: Integer;
begin
 if Index < 0 then Exit;

 if Index >= Length(fEvents) then begin
   OldCount := Length(fEvents);
   SetLength(fEvents, Index - 1);
   for i := OldCount - 1 to Length(fEvents) - 1 do begin
     fEvents[i].Name := "";
     fEvents[i].Event := nil;
   end;
 end;
 fEvents[Index].Event := Event;
end;

function TEventManager.GetUniversal: TEvent;
begin
 Result := fUniversal;
end;

procedure TEventManager.SetUniversal(const Event: TEvent);
begin
 fUniversal := Event;
end;

procedure TEventManager.Clean;
var
 i: Integer;
 Name: String;
begin
 if Length(fEvents) = 0 then Exit;

 i := 0;
 while i < Length(fEvents) do begin
   Name := Trim(fEvents[i].Name);
   if (Name = "") or
      (not Assigned(fEvents[i].Event)) then begin
     if i < Length(fEvents) - 1 then
       fEvents[i] := fEvents[Length(fEvents) - 1];
     SetLength(fEvents, Length(fEvents) - 1);
     Continue;
   end;
   Inc(i);
 end;
end;

procedure TEventManager.Call(const Name: String; const Sender: TBaseObject = nil; const Param: Cardinal = 0);
var
 Index: Integer;
begin
 Index := GetEventIndexByName(Name);

 if Index >= 0 then begin
   if Addr(fUniversal) <> nil then begin
     fUniversal(Sender, Param);
   end;
   if Addr(fEvents[Index].Event) <> nil then begin
     fEvents[Index].Param := Param;
     fEvents[Index].Call(Sender);
   end;
 end;
end;

function TEventManager.Count: Integer;
begin
 Result := Length(fEvents);
end;

function CreateEventManager(const Name: String = ""; const Parent: TBaseObject = nil): TEventManager;
begin
 Result := TEventManager.Create(Name, Parent);
end;

end.


Писалось на турбо делфи.


 
MBo ©   (2008-03-18 06:12) [1]

TEvent = procedure (Sender: TBaseObject; Param: Cardinal) of object

P.S. обычно геттеры для процедурных свойств (GetUniversal) не делают, можно обойтись fUniversal


 
Pir   (2008-03-18 06:16) [2]

Нет, of object не надо, используются процедуры вне классов. А геттер используется для того, чтобы обращаться к class var, находящейся в секции private.


 
Pir   (2008-03-18 06:18) [3]

Исходники (правда, немного староватая версия, но ошибка та же) тут: http://osvldm.narod.ru/Again.rar


 
Ega23 ©   (2008-03-18 06:25) [4]


> А геттер используется для того, чтобы обращаться к class
> var, находящейся в секции private.


Вот этой фразы вообще не понял.
Это что по-твоему, я не смогу поле в private-секции без Get прочитать???


 
Pir   (2008-03-18 06:29) [5]

А фиг его знает... Конструкция вида property Universal: TEvent read fUniversal write fUniversal в случае с class var не срабатывает у меня. А если сделать так, то явно не прокатит:

var
 EM: TEventManager;
begin
 EM := TEventManager.Create;
 EM.fUniversal := nil;
 EM.Free;
end;


 
MBo ©   (2008-03-18 06:44) [6]

Universal: TEvent read fUniversal write SetUniversal;


 
icWasya ©   (2008-03-18 10:09) [7]

В исходниках Delphi обычно проверяют Assigned(fUniversal)


 
Ega23 ©   (2008-03-18 10:31) [8]


> В исходниках Delphi обычно проверяют Assigned(fUniversal)


Потому что если попробуют поставить fUniversal =nil, то сначала выполнится fUniversal (это же процедура как-никак)...


 
Pir   (2008-03-18 15:41) [9]

Самый прикол в том, что даже если тип поменять с TEvent на PEvent = ^TEvent и заменить соотв. обращения, все равно не работает. Но если fUniversal объявить как class var - как швейцарские часы.


 
Ega23 ©   (2008-03-18 16:45) [10]

Я вот одного не могу понять: нафига такие сложности? Ну объяви свой TEvent как procedure of object, и не парься...



Страницы: 1 вся ветка

Текущий архив: 2008.04.27;
Скачать: CL | DM;

Наверх




Память: 0.5 MB
Время: 0.015 c
2-1207040118
Dima
2008-04-01 12:55
2008.04.27
Проблема со скачиванием файла, WinInet


2-1207050075
exe2k
2008-04-01 15:41
2008.04.27
Copyfile


2-1205474657
031178
2008-03-14 09:04
2008.04.27
Календарь


15-1204816041
Сатир
2008-03-06 18:07
2008.04.27
Марко Кэнту опубликовал открытое письмо...


15-1202637891
md10
2008-02-10 13:04
2008.04.27
140 v - что делать?