开发者

How to store a set in a TStringList Object?

I'm trying to store a set inside the object property (and read it) of a TStringList (I will also use it to store text associated to the set) but I get a invalid typecast for the set.

What's the best way to store a set inside a StringList object? Also, will this object need to be freed when destroying the StringList?

Here's some example code:

type
 TDummy = (dOne, dTwo, dThree);
 TDummySet = set of TDummy;


var
  DummySet: TDummySet;
  SL: TStringList;
begin
  开发者_StackOverflow社区SL := TStringList.Create;
  Try
    DummySet := [dOne, dThree];
    SL.AddObject('some string', TObject(DummySet)); // Doesn't work. Invalid typecast
  Finally
    SL.Free;
  End;
end;


First read the other answers - probably you'll find a less hacky solution.

But FTR: You can write

SL.AddObject('some string', TObject(Byte(DummySet)));

and

DummySet := TDummySet(Byte(SL.Objects[0]));

if you really want.

Note: You'll have to change the keyword Byte if you add enough elements to the TDummySet type. For example, if you add six more elements (so that there is a total of nine) you need to cast to Word.


I can't add non objects on that case.

What you can do, is create an object that have TDummySet as Field. Something like

TExemple = class
 DummySet = TDummySet;
end;

Or you can use a different approach:

Declarations:

  TDummy = (dOne, dTwo, dThree);
  TDummySet = set of TDummy;
  PDummySet = ^TDummySet;

How to use:

var
  DummySet: PDummySet;
 begin
  New(DummySet);
  DummySet^ := [dOne, dThree];


You should not store a set via TStringList.Objects because what Objects use (TObject) is a 32 bit value type and sets can be represented up to 256 bits depending on the size of the set. That's probably why the compiler doesn't even allow casting.

A better way to serialize sets is using RTTI. I am not sure where VCL exposes its builtin set serialization mechanism but JCL has a JclRTTI unit with JclSetToStr and JclStrToSet functions.

var 
  fs: TFontStyles;
begin 
  JclStrToSet(TypeInfo(TFontStyles), fs, 'fsBold, fsItalic'); // from string
  Showessage(JclSetToStr(TypeInfo(TFontStyles), fs));         // to string  
end;


I don't think a stringlist is the way to go. Why not an array of TDummySet? And no, there is no need to free it because the set is not an object.

var
  Test: Array of TDummySet;

SetLength(Test, 2);
Test[0] := [dOne, dThree];
Test[1] := [dTwo];

When you're done:

SetLength(Test, 0);


You cannot make a typecast from your set to a TObject, because your variable is not a pointer.

You have to store a pointer to your variable in the TStringList. In that case, you'll have to allocate and deallocate it manually too.

Try something like this:

type
  TEnum = (one, two, three);
  TSet = set of TEnum;
  PSet = ^TSet;
var s: TStringList;
    p: PSet;
begin
  s := TStringList.Create;
  p := AllocMem(SizeOf(TSet));
  p^ := [two, three];
  S.AddObject('a', TObject(p));

  // bla bla bla

  // Here you read the set in the string list
  if (two in PSet(S.Objects[0])^)) then begin
    // your checks here
  end

  ...
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜