I'm currently creating soap wrappers for some Delphi functions so that we can easily use them from PHP, C# and Delphi.
I wonder what's the best way to expose sets.
type
TCountry = (countryUnknown,countryNL,countryD,countryB,countryS,countryFIN,countryF,countryE,countryP,countryPl,countryL);
TCountrySet = set of TCountry;
function GetValidCountrySet(const LicensePlate:string; const PossibleCountriesSet:TCountrySet):TCountrySet;
I'm currently wrapping it like this for the soap server:
type
TCountryArray = array of TCountry;
function TVehicleInfo.GetValidCountrySet(const LicensePlate:string; const PossibleCountriesSet:TCountryArray):TCountryArray;
It works, but I need to write a lot of useless and ugly code to convert sets-->arrays and arrays-->sets.
Is there an easier, more elegant, or more generic way to do this?
You could use TypInfo and use a bit of clever casting.
uses TypInfo;
type
TCountry = (cnyNone, cnyNL, cnyD, cnyGB, cnyF, cnyI);
TCountrySet = set of TCountry;
TCountryArray = array of TCountry;
TEnumIntegerArray = array of Integer;
TEnumByteArray = array of Byte;
function GetEnumNamesInSet(const aTypeInfo: PTypeInfo; const aValue: Integer; const aSeparator: string = ','): string;
var
IntSet: TIntegerSet;
i: Integer;
begin
Result := '';
Integer( IntSet ) := aValue;
for i := 0 to SizeOf(Integer) * 8 - 1 do begin
if i in IntSet then begin
if Result <> '' then begin
Result := Result + ',';
end;
Result := Result + GetEnumName(aTypeInfo, i);
end;
end;
end;
function SetToIntegerArray(const aTypeInfo: PTypeInfo; const aValue: Integer): TEnumIntegerArray;
var
IntSet: TIntegerSet;
i: Integer;
begin
SetLength(Result, 0);
Integer( IntSet ) := aValue;
for i := 0 to SizeOf(Integer) * 8 - 1 do begin
if i in IntSet then begin
SetLength(Result, Length(Result) + 1);
Result[Length(Result) - 1] := i;
end;
end;
end;
function SetToByteArray(const aTypeInfo: PTypeInfo; const aValue: Byte): TEnumByteArray;
var
IntSet: TIntegerSet;
i: Integer;
begin
SetLength(Result, 0);
Integer( IntSet ) := aValue;
for i := 0 to SizeOf(Byte) * 8 - 1 do begin
if i in IntSet then begin
SetLength(Result, Length(Result) + 1);
Result[Length(Result) - 1] := i;
end;
end;
end;
Then use as:
procedure TEnumForm.FillMemo;
var
Countries: TCountrySet;
// EIA: TEnumIntegerArray;
EBA: TEnumByteArray;
CA: TCountryArray;
i: Integer;
cny: TCountry;
begin
Countries := [cnyNL, cnyD];
CountriesMemo.Text := GetEnumNamesInSet(TypeInfo(TCountry), Byte(Countries));
// if SizeOf(TCountry) > SizeOf(Byte) then begin
// EIA := SetToIntegerArray(TypeInfo(TCountry), Integer(Countries));
// end else begin
EBA := SetToByteArray(TypeInfo(TCountry), Byte(Countries));
// end;
CountriesMemo.Lines.Add('====');
CountriesMemo.Lines.Add('Values in Array: ');
// if SizeOf(TCountry) > SizeOf(Byte) then begin
// CA := TCountryArray(EIA);
// end else begin
CA := TCountryArray(EBA);
// end;
for i := 0 to Length(CA) - 1 do begin
CountriesMemo.Lines.Add(IntToStr(Ord(CA[i])));
end;
CountriesMemo.Lines.Add('====');
CountriesMemo.Lines.Add('Names in Array: ');
// if SizeOf(TCountry) > SizeOf(Byte) then begin
// CA := TCountryArray(EIA);
// end else begin
CA := TCountryArray(EBA);
// end;
for i := 0 to Length(CA) - 1 do begin
cny := CA[i];
CountriesMemo.Lines.Add(GetEnumName(TypeInfo(TCountry), Ord(cny)));
end;
end;
You will need to select the proper casting based on the size of the TCountry enum. If it has 8 members it will be a Byte, any bigger and it will be an Integer. Anyway, Delphi will complain on the cast of Byte(Countries) or Integer(Countries) when you get it wrong.
Please note: The functions now take the TypeInfo of TCountry - the elements of the TCountrySet. They could be changed to take TypeInfo(TCountrySet). However that would mean having the functions work out what elements are in the set and I simply haven't had the time or inclination to do that yet.
Soap should be used in a platform and language agnostic way - I would design all data transfer objects (DTO) based on simple types e.g. array of string
, without language specific features. Then map the DTO to the matching business objects. This also will give you an 'anticorruption layer'.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With