Polymorphism and properties - delphi

I'm trying to use polymorphism and create a property that should return different types depending on what type of object it is.
Why is there this compiler warning for the code below:
[Warning: Constructing a class "TTimeField" with abstract method "SetValue"]
More important, how can I make this work so Value can be assigned a TDateTime when a TTimeField is created? As it is, there is a message about "type mismatch".
TBaseField = class
private
function GetValue: string; virtual; abstract;
procedure SetValue(AValue: string); virtual; abstract;
public
property Value: string read GetValue write SetValue;
end;
{ TTimeField }
TTimeField = class(TBaseField)
private
FValue : TDateTime;
function GetValue: TDateTime; override;
procedure SetValue(AValue: TDateTime); override;
public
property Value: TDateTime read GetValue write SetValue;
end;
implementation
function TTimeField.GetValue: TDateTime;
begin
Result:= FValue;
end;
procedure TTimeField.SetValue(AValue: TDateTime);
begin
FValue:= AValue;
end;
EDIT: Below, with the use of strings I achieved the functionality needed, but if the code above had worked it had meant a gain in performance.
TBaseField = class
private
procedure SetStrValue(AValue: string); virtual; abstract;
function GetStrValue: string; virtual; abstract;
public
property AsString: string read GetStrValue write SetStrValue;
end;
TTimeField = class(TBaseField)
private
FValue : TDateTime;
function GetStrValue: string; override;
procedure SetStrValue(AValue: string); override;
public
property AsString: string read GetStrValue write SetStrValue;
end;
function TTimeField.GetStrValue: string;
begin
Result:= DateTimeToStr(FValue);
end;
procedure TTimeField.SetStrValue(AValue: string);
begin
FValue:=StrToDateTime(AValue);
end;

I think your problem is that you're not actually overriding any method; your new method has a different signature. Therefore it is actually an overload. In your example, having TBaseField doesn't really help you in any way. The subclass doesn't use any of its methods, nor does it provide any extra functionality.
Polymorphism is about varying implementations for a given interface (as in method signatures) without the caller needing to knowing about that.
Looking at your example, it might just be that you're not necessarily looking for polymorphism, but rather for a way to implement similar methods/properties for various data types with as little code as possible. That's where generics usually prove more useful.
Say that all field classes need to store a value of their own type, which should be possible to set and retrieve. Then you can define a generic TField<T> where T is a "placeholder" for the type of data that the field should work with. You will be able to give it a getter and setter, as well as a property, which will be generic too. As such, you'll only need to define them once for all kinds of fields you'll end up using. These methods may contain whatever logic is shared by all fields. You may, however, still subclass a generic type to add specific functionality to a certain type, or to hide the fact that you rely on generics.
A simple example:
type
TField<T> = class
private
FValue: T;
protected
function GetValue: T; virtual;
procedure SetValue(const AValue: T); virtual;
public
property Value: T read GetValue write SetValue;
end;
TDateTimeField = TField<TDateTime>;
TTrimmingStringField = class(TField<string>);
protected
function SetValue(const AValue: string); override;
end;
// Now use these fields as you'd expect
implementation
{ TField<T> }
function TField<T>.GetValue: T;
begin
Result := FValue;
end;
procedure TField<T>.SetValue(const AValue: T);
begin
FValue := AValue;
end;
{ TTrimmingStringField }
procedure TTrimmingStringField.SetValue(const AValue: string);
begin
inherited SetValue(Trim(AValue));
end;

Polymorphism is used with methods rather than properties. You can define a property that has virtual getter and setter methods, and then use polymorphism on those getter and setter methods.
However, polymorphic methods are not allowed to change the type of the arguments or the return value. Why not?
Well, suppose we write this code:
type
TMyBaseClass = class
public
procedure Foo(Arg: string); virtual;
end;
....
var
obj: TMyBaseClass;
....
obj.Foo('bar');
One of the tenets of polymorphism is that obj can be an instance of TMyBaseClass or indeed any class derived from TMyBaseClass. The compiler does not need to know the actual type of obj, only that it is derived from TMyBaseClass. The type is only known at runtime, and polymorphic virtual method despatch ensures that the derived method is called.
This means that it would make no sense for Foo to accept arguments of any type other than that declared when the virtual method was first introduced.
What you need is something called a variant type. A variant type is one that can represent many different types. For instance, any decent variant type will be able to represent integers, floating point values, strings, dates and times and so on. In Delphi you would use something like the COM Variant type, or the more recently added TValue. In Free Pascal, I'm not so sure what the prevailing variant type is.

Related

How to let the IDE know that I use ancestor variable?

For simplicity, I only have 2 classes TParent and TChild.
TParent = class
protected
FValue : Integer;
end;
TChild = class(TParent)
public
property Value : Integer read FValue;
end;
If the TChild property Value uses the TParent variable FValue which is in another unit, the IDE always creates new variable when using auto-complete, which is a problem when adding new properties or methods and may cause unwanted errors.
TChild = class(TParent)
private
FValue: Integer;
public
property Value : Integer read FValue;
end;
However, if TParent and TChild are in the same unit, everything works fine. Is there any way to prevent this if I don't have the ability to move both classes to the same unit? Also I don't have access to a unit containing TParent. In this case, TChild is a component derived from TCustomGrid.
This is just the nature of inheritance, more specifically, field visibility. The simple solution would be to introduce a property getter function with a higher visibility. For example...
TParent = class
protected
FValue : Integer;
public
function GetValue: Integer;
end;
TChild = class(TParent)
public
property Value : Integer read GetValue;
end;
...
function TParent.GetValue: Integer;
begin
Result:= FValue;
end;
Code completion is just following these same rules - it doesn't have visibility of the parent's field, so it generates a new one.

How to use TObjectList for arbitrary class type?

I'm still a bit fuzzy with generics in Delphi, but have been using TObjectList<> quite widely. Now I have a situation where I have a base class with such a private field, but needs to be created for an arbitrary class, also inherited from another base.
To clarify, I have two base classes:
type
TItem = class;
TItems = class;
TItemClass = class of TItem;
TItem = class(TPersistent)
private
FSomeStuffForAllIneritedClasses: TSomeStuff;
end;
TItems = class(TPersistent)
private
FItems: TObjectList<TItem>;
FItemClass: TItemClass;
public
constructor Create(AItemClass: TItemClass);
destructor Destroy; override;
function Add: TItem;
...
end;
This pair of classes is then further inherited into more specific classes. I'd like the object list to be shared for all of them, while each holds actually a different type internally.
type
TSomeItem = class(TItem)
private
FSomeOtherStuff: TSomeOtherStuff;
...
end;
TSomeItems = class(TItems)
public
function Add: TSomeItem; //Calls inherited, similar to a TCollection
procedure DoSomethingOnlyThisClassShouldDo;
...
end;
Now the problem is when it comes to creating the actual object list. I'm trying to do it like this:
constructor TItems.Create(AItemClass: TItemClass);
begin
inherited Create;
FItemClass:= AItemClass;
FItems:= TObjectList<AItemClass>.Create(True);
end;
However, the code insight complains about this:
Undeclared Identifier AItemClass
Even more, the compiler has yet a different complaint:
Undeclared Identifier TObjectList
Where, I do in fact have System.Generics.Collections used in this unit.
What am I doing wrong here, and how should I do this instead?
Make TItems generic:
TItems<T: TItem, constructor> = class(TPersistent)
private
FItems: TObjectList<T>;
public
constructor Create;
destructor Destroy; override;
function Add: T;
...
end;
constructor TItems.Create;
begin
inherited Create;
FItems:= TObjectList<T>.Create(True);
end;
function TItems<T>.Add: T;
begin
Result := T.Create;
FItems.Add(Result);
end;
If you inherit, simply put the correct generic parameter:
TSomeItems = class(TItems<TSomeItem>)
public
procedure DoSomethingOnlyThisClassShouldDo;
...
end;
The TObjectList is not meant to be used in that manner. The fact that it was originally defined as TObjectList<TItem> means that it will expect you to create it this way as well. It needs to be defined with the precise class you intend to create it as.
Instead, just create it with TItem, and then whenever you create a new item which is supposed to be added to this list, then you create it using the class type. Any time you need to access the items in this list, just cast them on the fly.
For example...
Result:= FItemClass.Create;
FItems.Add(Result);
...can be the contents of your Add function.

Dynamically created object (providing its classname as a string) do not call its constructor

Here is the object:
TCell = class(TPersistent)
private
FAlignmentInCell :byte;
public
constructor Create; virtual;
published
property AlignmentInCell:byte read FAlignmentInCell write FAlignmentInCell;
end;
this is its constructor:
constructor TCell.Create;
begin
inherited;
FAlignmentInCell:=5;
end;
Here is a function, which dynamically creates any object derived form TPersistent (parameter is class name provided as a string)
function CreateObjectFromClassName(AClassName:string):TPersistent;
var DynamicObject:TPersistent;
TempObject:TPersistent;
DynamicPersistent:TPersistent;
DynamicComponent:TComponent;
PersistentClass:TPersistentclass;
ComponentClass:TComponentClass;
begin
PersistentClass:=TPersistentclass(FindClass(AClassName));
TempObject:=PersistentClass.Create;
if TempObject is TComponent then
begin
ComponentClass:=TComponentClass(FindClass(AClassName));
DynamicObject:=ComponentClass.Create(nil);
end;
if not (TempObject is TComponent) then
begin
DynamicObject:=PersistentClass.Create; // object is really TCell, but appropriate constructor seems to be not called.
end;
result:=DynamicObject;
end;
My idea is to create new Cell (TCell) like this:
procedure TForm1.btn1Click(Sender: TObject);
var p:TPersistent;
begin
p := CreateObjectFromClassName('TCell');
ShowMessage(IntToStr(TCell(p).AlignmentInCell)); // it is 0. (Why?)
end;
When I want to check AlignmentInCell property I get 0, but I expected 5. Why? Is there way to fix it?
This is similar to a recent question.
You use TPersistentClass. But TPersistent does not have a virtual constructor, so the normal constructor for TPersistent is called, which is the constructor it inherits from TObject.
If you want to call the virtual constructor, you will have to declare a
type
TCellClass = class of TCell;
Now you can modify CreateObjectFromClassName to use this metaclass instead of TPersistenClass, and then the actual constructor will be called.
Also, TempObject is never freed. And instead of is, I would rather use InheritsFrom.
I did not test the following, but it should work:
function CreateObjectFromClassName(const AClassName: string; AOwner: TComponent): TPersistent;
var
PersistentClass: TPersistentclass;
begin
PersistentClass := FindClass(AClassName);
if PersistentClass.InheritsFrom(TComponent) then
Result := TComponentClass(PersistentClass).Create(AOwner)
else if PersistentClass.InheritsFrom(TCell) then
Result := TCellClass(PersistentClass).Create
else
Result := PersistentClass.Create;
end;
The compiler can't know for sure what value your variable of type TPersistentClass will hold at run time. So he assumes that it is exactly that: a TPersistentClass.
TPersistentClass is defined as a class of TPersistent. TPersistent has no virtual constructor, the compiler will therefore not include a call to dynamically look up the address of the constructor in the VMT of the actual class, but a 'hard-coded' call to the only matching constructor TPersistent has: the one it inherits from its base class TObject.
It might be a decision with reasons I don't know, but if you had chosen to define TCell as following
TCell = class(TComponent)
private
FAlignmentInCell: byte;
public
constructor Create(AOwner: TComponent); override;
published
property AlignmentInCell:byte read FAlignmentInCell write FAlignmentInCell;
end;
you wouldn't need TempObject and all the decision making in your CreateObjectFromClassName function (and the possible leaks as pointed out by others):
function CreateObjectFromClassName(AClassName:string): TComponent;
var
ComponentClass:TComponentClass;
begin
ComponentClass:=TComponentClass(FindClass(AClassName));
Result := ComponentClass.Create(nil);
end;
And make sure to manage the Results life-time as it has no Owner.

Delphi: Using function from main class in a subclass

On the new side of writing classes and have a little problem which I have tried researching but still no answer.
I want to create one instance of a class which creates multiple subclasses which creates subclasses of their own. The idea is to use code like this in main program:
procedure TForm1.Button1Click(Sender: TObject);
var
Temp : Integer;
begin
MainClass := TMainClass.Create(Form1);
Temp := MainClass.SubClass1.SubSubClass1.SomeValue;
end;
The main class looks like this and is created in seperate file:
TMainClass = class(TObject)
private
FSubClass1 : TSubClass1;
public
ValueFromAnySubClass : Integer;
property SubClass1 : TSubClass1 read FSubClass1 write FSubClass1;
procedure SetSomeValueFromMainClass(Value : Integer);
end;
...
...
...
procedure TMainClass.SetSomeValueFromMainClass(Value : Integer);
begin
ValueFromAnySubClass := Value;
end;
The sub class also in seperate file:
TSubClass1 = class(TObject)
private
FSubSubClass1 : TSubSubClass1;
public
property SubSubClass1 : TSubSubClass1 read FSubSubClass1 write FSubSubClass1;
end;
And now for the sub sub class also in seperate file:
TSubSubClass1 = class(TObject)
private
SomeValue : Integer;
function GetSomeValue : Integer;
procedure SetSomeValue(Value : Integer);
public
property SomeValue : Integer read GetSomeValue write SetSomeValue;
end;
...
...
...
procedure TSubSubClass1.SetSomeValue(Value : Integer);
begin
SetSomeValueFromMainClass(Value); <<< Error Here <<<
end;
How do I get to use the functions and procedures from the main class in my sub classes?
You don't need a subclass to use a function from another class. Also your sample code has not used subclasses at all. A proper subclass automatically has access to all public and proteced functions of its ancestors.
As David has already pointed out, there are serious flaws in your intended deisgn.
Furthermore, based on your comment:
The classes all perform vastly different functions but need to write data to a piece of hardware at the end of the day. The data is read from the hardware and kept in memory to work with until its written back to the hardware component once all work is completed. The procedure in the main class takes care of writing real time data to the hardware whenever it is required by any of the subclasses.
to David's answer: you don't need subclasses at all.
All you need is a public method on your hardware class. And for each instance of your other classes to have a reference to the correct instance of your hardware class.
type
THardwareDevice = class(TObject)
public
procedure WriteData(...);
end;
TOtherClass1 = class(TObject)
private
FDevice: THardwareDevice;
public
constructor Create(ADevice: THardwareDevice);
procedure DoSomething;
end;
constructor TOtherClass1.Create(ADevice: THardwareDevice);
begin
FDevice := ADevice;
end;
procedure TOtherClass1.DoSomething;
begin
//Do stuff, and maybe you need to tell the hardware to write data
FDevice.WriteData(...);
end;
//Now given the above you can get two distinct object instances to interact
//as follows. The idea can be extended to more "other class" types and instances.
begin
FPrimaryDevice := THardwareDevice.Create(...);
FObject1 := TOtherClass1.Create(FPrimaryDevice);
FObject1.DoSomething;
//NOTE: This approach allows extreme flexibility because you can easily
// reference different instances (objects) of the same hardware class.
FBackupDevice := THardwareDevice.Create(...);
FObject2 := TOtherClass1.Create(FBackupDevice);
FObject2.DoSomething;
...
end;
The design looks really poor. You surely don't want to have all these classes knowing all about each other.
And any time you see a line of code with more than one . operator you should ask yourself if the code is in the right class. Usually that indicates that the line of code that has multiple uses of . should be in one of the classes further down the chain.
However, if you want to call a method, you need an instance. You write:
procedure TSubSubClass1.SetSomeValue(Value : Integer);
begin
SetSomeValueFromMainClass(Value);
end;
And naturally this does not compile. Because SetSomeValueFromMainClass is not a method of TSubSubClass1. Rather SetSomeValueFromMainClass is a method of TMainClass. So, to call that method, you need an instance of TMainClass.
Which suggests that, if you really must do this, that you need to supply to each instance of TSubSubClass1 an instance of TMainClass. You might supply that in the constructor and make a note of the reference.
Of course, when you do this you now find that your classes are all coupled together with each other. At which point one might wonder whether or not they should be merged.
I'm not saying that merging these classes is the right design. I would not like to make any confident statement as to what the right design is. Perhaps what you need is an interface that promises to implement the setter as a means to decouple things. All I am really confident in saying is that your current design is not the right design.
As far as I know Subclass word is usually using in inheritance concept but the code you wrote are some compound classes. As you may see the constructor of many classes in Delphi have an argument which named AOwner that may be TComponent or TObject or ...
If you define the constructors of your TSubclass1 and TSubSubClass1 like as follow and Change the Owner of classes that you defined as properties to Self in set functions you may access to your TMainClass by typecasting the Owner property.
I changed your code a little to just work as you want, but I suggest change your design.
TSubSubClass1 = class(TObject)
private
FOwner: TObject;
function GetSomeValue:Integer;
procedure SetSomeValue(const Value: Integer);
procedure SetOwner(const Value: TObject);
public
constructor Create(AOwner:TObject);reintroduce;
property Owner:TObject read FOwner write SetOwner;
property SomeValue : Integer read GetSomeValue write SetSomeValue;
end;
TSubClass1 = class(TObject)
private
FSubSubClass1: TSubSubClass1;
FOwner:TObject;
procedure SetSubSubClass1(const Value: TSubSubClass1);
procedure SetOwner(const Value: TObject);
public
constructor Create(AOwner:TObject);reintroduce;
property Owner:TObject read FOwner write SetOwner;
property SubSubClass1 : TSubSubClass1 read FSubSubClass1 write SetSubSubClass1;
end;
TMainClass = class(TObject)
private
FSubClass1: TSubClass1;
procedure SetSubClass1(const Value: TSubClass1);
public
ValueFromAnySubClass : Integer;
constructor Create;
property SubClass1 : TSubClass1 read FSubClass1 write SetSubClass1;
procedure SetSomeValueFromMainClass(Value : Integer);
end;
implementation
{ TSubSubClass1 }
constructor TSubSubClass1.Create(AOwner: TObject);
begin
Owner:=AOwner;
end;
function TSubSubClass1.GetSomeValue: Integer;
begin
Result:=TMainClass(TSubClass1(Self.Owner).Owner).ValueFromAnySubClass;
end;
procedure TSubSubClass1.SetOwner(const Value: TObject);
begin
FOwner := Value;
end;
procedure TSubSubClass1.SetSomeValue(const Value: Integer);
begin
TMainClass(TSubClass1(Self.Owner).Owner).SetSomeValueFromMainClass(Value);
end;
{ TSubClass1 }
constructor TSubClass1.Create(AOwner: TObject);
begin
Owner:=AOwner;
FSubSubClass1:=TSubSubClass1.Create(Self);
end;
procedure TSubClass1.SetOwner(const Value: TObject);
begin
FOwner := Value;
end;
procedure TSubClass1.SetSubSubClass1(const Value: TSubSubClass1);
begin
FSubSubClass1 := Value;
FSubSubClass1.Owner:=Self;
end;
{ TMainClass }
constructor TMainClass.Create;
begin
FSubClass1:=TSubClass1.Create(Self);
end;
procedure TMainClass.SetSomeValueFromMainClass(Value: Integer);
begin
ValueFromAnySubClass := Value;
end;
procedure TMainClass.SetSubClass1(const Value: TSubClass1);
begin
FSubClass1 := Value;
FSubClass1.Owner:=Self;
end;
you must put the proper filename in uses part of implementation.

Why use property in a class?

I was just wondering about why should I use property in a class instead of "normal" variables (class attributes?). What I mean is this:
TSampleClass = class
public
SomeInfo: integer;
end;
TPropertyClass = class
private
fSomeInfo: integer;
public
property SomeInfo: integer read fSomeInfo write fSomeInfo;
end;
What is the big difference? I know that I can define getter and setter methods for getting or saving the property respectively, but that is possible even without the variable being a "property".
I tried searching for why to use it, but nothing useful came up, so I'm asking here.
Thank you
This is just a very simple example of a specific case, but still, it is a very common case.
If you have a visual control, you might need to repaint the control when you change a variable/property. For instance, let's say your control has a BackgroundColor variable/property.
The simplest way of adding such a variable/property is to let it be a public variable:
TMyControl = class(TCustomControl)
public
BackgroundColor: TColor;
...
end;
And in the TMyControl.Paint procedure, you paint the background using the value of the BackgroundColor. But this doesn't do it. Because if you change the BackgroundColor variable of an instance of the control, the control doesn't repaint itself. Instead, the new background colour will not be used until the next time the control redraws itself for some other reason.
So you have to do it like this:
TMyControl = class(TCustomControl)
private
FBackgroundColor: TColor;
public
function GetBackgroundColor: TColor;
procedure SetBackgroundColor(NewColor: TColor);
...
end;
where
function TMyControl.GetBackgroundColor: TColor;
begin
result := FBackgroundColor;
end;
procedure TMyControl.SetBackgroundColor(NewColor: TColor);
begin
if FBackgroundColor <> NewColor then
begin
FBackgroundColor := NewColor;
Invalidate;
end;
end;
and then the programmer using the control has to use MyControl1.GetBackgroundColor to obtain the colour, and to use MyControl1.SetBackgroundColor to set it. That's awkward.
Using properties, you can have the best of both worlds. Indeed, if you do
TMyControl = class(TCustomControl)
private
FBackgroundColor: TColor;
procedure SetBackgroundColor(NewColor: TColor);
published
property BackgroundColor: TColor read FBackgroundColor write SetBackgroundColor;
end;
...
procedure TMyControl.SetBackgroundColor(NewColor: TColor);
begin
if FBackgroundColor <> NewColor then
begin
FBackgroundColor := NewColor;
Invalidate;
end;
end;
then
from the programmer's point of view, he can both read and set the background colour using a single identifier, the MyControl1.BackgroundColor property, and
the control is repainted when he sets it!
There are real-life advantages:
Properties can be changed to be read/write/read'n'write easily, without need to hassle with separate Getters and Setters all over the code;
Properties can be made public/published in child classes by just adding one line in initialization section;
Properties are more friendly when it comes to setting fields, compare "Label.Font.SetSize(14)" with "Label.Font.Size := 14", you can align ":=" with tabs/spaces and code will be much more readable;
EDIT: Another thing I thought of, properties force you to limit Get/Set methods to only 1 parameter, which is good for OOP. Compare that to some over-engineered functions:
GetItem(Index:integer; ForcedIndex:boolean=false):TItem //Forced index to get any value
GetItem(Index:integer; out Res:PItem):boolean //Result signals if out pointer is valid
I know that I can define getter and setter methods for getting or saving the property respectively, but that is possible even without the variable being a "property".
Well, no. Setters and getters are just normal methods that are called as such only once they are used as the read and write members of a property. Not having a property means not having a getter or a setter, even if they are named as such.
Furthermore; setters and getters are typically declared private or protected. So being able to call them when you use a public field instead of using a public property would require to move those methods to the public section.
Also, a big difference between fields and properties is the ability to be published and thus can be used in the object inspector. Fields (of other types then class or interface) can not be declared as published.
Properties can also be of great importance - or be usefull - in inheritance. Technically, you can't override a property, but you can mimic override in several ways. Some examples where property Name can be called from TDescendant, each with its own purpose:
1) Abstraction:
TBase = class(TObject)
protected
function GetName: String; virtual; abstract;
procedure SetName(const Value: String); virtual; abstract;
public
property Name: String read GetName write SetName;
end;
TDescendant = class(TBase)
private
FName: String;
protected
function GetName: String; override;
procedure SetName(const Value: String); override;
end;
2a) Protection (like Krom mentioned, ):
TBase = class(TObject)
private
FName: String;
function GetName: String;
procedure SetName(const Value: String);
protected
property Name: String read GetName write SetName;
end;
TDescendant = class(TBase)
public
property Name;
end;
2b)
TBase = class(TObject)
private
FName: String;
protected
function GetName: String;
procedure SetName(const Value: String);
end;
TDescendant = class(TBase)
public
property Name: String read GetName write SetName;
end;
By combinination of the above, you could change the behaviour of properties for descendant classes.
It is just a good programming practice to isolate the very "innards" of your class from the outside world. In addition, information about published properties are stored into RTTI generated for the class and can be accessed by their name, enumerated etc. This feature is used for example when reading a form from its serialized resource form.
One of main reason of using properties (regardless of it's more OO) is the validation of the input, for example if you need to limit the age of an employee class to be in valid range like 18..40
TEmp = class
private
FName: string;
FAge: Integer;
procedure SetAge(const Value: Integer);
procedure SetName(const Value: string);
published
property Name:string read FName write SetName;
property Age:Integer read FAge write SetAge;
end;
.....
procedure TEmp.SetAge(const Value: Integer);
begin
if not (Value in [18..40]) then
raise Exception.Create('Age must be between 18 and 40')
else
FAge := Value;
end;
You cant monitor the change in a variable without a property.
your read/writes for property dont have to be a variable they can be functions. And then you can manage the "onChange" of a property.
eg
TmyChange = procedure(Sender: Tobject) of object;
private
Fchange : TmyChange;
public
property SomeInfo: integer read getFoo write setFoo;
property onChange : TmyChange read Fchange write Fchange;
function getFoo : integer
begin
return localFoo;
end;
function setFoo (value : integer)
begin
// validate incoming value
localFoo=value;
if assigned(Fchange) then Fchange(self);
end;

Resources