Delphi property read/write
Asked Answered
L

4

6

is it possible to have different kind of results when declaring property in delphi class?

Example:

property month: string read monthGet(string) write monthSet(integer);

In the example, I want, with the property month, that when I : READ, I get a string; SET, I set an integer;

Lantha answered 31/10, 2014 at 10:22 Comment(7)
No. It is not. That's why there are casting properties and functions like AsString. If you have more recent version of Delphi, you can define a type like TMonth and write helper functions for different sorts of casting. Which version of Delphi do you have ?Trisa
So, How can I do it?Lantha
Just look at the docs docwiki.embarcadero.com/RADStudio/en/…Directoire
FWIW, the convention for property XYZ is to define the getter as function GetXYZ: SomeType and the setter as procedure SetXYZ(const Value: SomeType).Burier
Delphi/Pascal properties are deeply linked to RTTI so the getter and the setter have to work on the same type. Maybe, and I know at least one, some other lang allow such overloading, but it's mostly because the "property" attribute (for those lang.) is more a syntactic sugar (e.g: using the assign operator instead of calling the setter with parenthesis).State
You could also resort to Variant type.Colleague
@FreeConsulting - Then (s)he would have two problems instead of one.Canotas
D
8

The closest you can get is to use Operator Overloading but the Getter/Setter must be the same type. There is no way to change that.

program so_26672343;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils;

type
  TMonth = record
  private
    FValue: Integer;
    procedure SetValue( const Value: Integer );
  public
    class operator implicit( a: TMonth ): string;
    class operator implicit( a: Integer ): TMonth;
    property Value: Integer read FValue write SetValue;
  end;

  TFoo = class
  private
    FMonth: TMonth;
  public
    property Month: TMonth read FMonth write FMonth;
  end;

  { TMonth }

class operator TMonth.implicit( a: TMonth ): string;
begin
  Result := 'Month ' + IntToStr( a.Value );
end;

class operator TMonth.implicit( a: Integer ): TMonth;
begin
  Result.FValue := a;
end;

procedure TMonth.SetValue( const Value: Integer );
begin
  FValue := Value;
end;

procedure Main;
var
  LFoo: TFoo;
  LMonthInt: Integer;
  LMonthStr: string;
begin
  LFoo := TFoo.Create;
  try
    LMonthInt := 4;
    LFoo.Month := LMonthInt;
    LMonthStr := LFoo.Month;
  finally
    LFoo.Free;
  end;
end;

begin
  try
    Main;
  except
    on E: Exception do
      Writeln( E.ClassName, ': ', E.Message );
  end;

end.
Directoire answered 31/10, 2014 at 10:45 Comment(4)
I agree that this is a possibility, and I thought of it too, but ISTM a little bit too much, compared to two properties or calling setters and getters directly.Burier
If you look at the whole concept of an application it is not too much. The domain-types (ValueObjects) are defined only once and were used all over the application. This small sample indeed looks like firing rockets on birdsDirectoire
If the application has Month as one of the central types, then it makes sense. Otherwise it is a bit too much, IMO. It is an elegant concept to define a type as a record with implicit converters, no doubt.Burier
I've used this solution for many things, including my own TDateTimeRec, TDateRec, TTimeRec, etc. Also the same for TVersion and TConnectionString, all records with implicit functions. Such a clever way of casting one value easily into different types :-) Also allowed me to put in some extra functions such as TDateTimeRec.FriendlyDate: String; which returns for example Friday October 31st 2014Agram
B
4

That is not possible. But properties do not have to correspond to internal storage directly, so you can do:

private
  FMonth: Integer;
  function GetMonthName: string;
...
  property Month: Integer read FMonth write FMonth;
  property MonthName: string read GetMonthName;
...

procedure TMyClass.GetMonthName: string;
begin
  // code that finds name that corresponds to value of FMonth and returns it in Result.
end;

In other words, you'll have to use two properties, one write-only (or normal), one read-only.

Burier answered 31/10, 2014 at 10:35 Comment(3)
Sorry I have started to write my answer before yours appeared.Canotas
No problem. The solution is pretty obvious, so that two or more came to that conclusion is not unexpected.Burier
If you allow both writing to the field directly and reading from it you could skip the first property and expose the field instead. I agree that yours is the book solution, but I'm reluctant to define a property for each and every field of my form.Demonography
F
1

There's no way to do that for a property. A property has a single type.

The obvious way to achieve you goal is to have getter and setter functions that you use directly.

function GetMonth: string;
procedure SetMonth(Value: Integer);

You might decide to make the type part of the name to reduce confusion in the calling code. Say GetMonthStr and SetMonthOrd.

You could expose these functions as two separate properties. One read only, the other write only.

Fideicommissum answered 31/10, 2014 at 10:31 Comment(2)
"You could expose these functions as two separate properties" Nice idea ;-)Dorsett
@JanDoggen Exactly the solution I have proposed. :DCanotas
C
1

You can't directly do that in Delphi.


What you can do is having a "casting property" like:

private
  //...
  intMonth: integer
  //...
public
  //...
  property StrMonth: string read GetStrMonth write SetStrMonth;
  property IntMonth: integer read intMonth write intMonth;
  //...
end;

function YourClass.GetStrMonth: string;
begin
  case intMonth of
    1: Result := "January";
    //...
  end;
end;

procedure YourClass.SetStrMonth(Value: string);
begin
  if StrMonth = "January" then
    intMonth := 1;
    //...
  end;
end;
Canotas answered 31/10, 2014 at 10:37 Comment(1)
You can't use the same name for a field and its property; it won't compile. Capitalizing the property won't save you either as Pascal is case-insensitive. Best practice is to prefix the field with an "F", like Rudy did.Demonography

© 2022 - 2024 — McMap. All rights reserved.