将字符串转换为设置类型

时间:2013-07-16 02:04:41

标签: delphi fpc

在我的应用程序中,我定义了许多集合:

eBlockTypes = (btNone,btUndefined,btStone, btYellowFlower, btWoodBrown...);

sMinerals = set of eBlockTypes; 

var
  mineralsRare: sMinerals;
  mineralsPlants: sMinerals;
  mineralsAll: sMinerals;
  mineralsDeep: sMinerals;
  mineralsWalkable: sMinerals;
  mineralsDiggable: sMinerals; 

然后我有一个将'sMinerals'作为其中一个字段的对象。从文件加载对象属性时是否可以读取set的'name'?

编辑:更多细节。假设文件中的对象定义如下:

[item]
Computer
[requires]
3 Circuit board
1 Medium CPU
3 Plastic
[placement]
mineralsWalkable

所以我可以解析文件并读取除了'mineralsWalkable'之外的所有属性。 我知道我可以将该字符串与一些保存所有集合名称的TStrings进行比较,但静止是:是否可以通过将字符串转换为变量来获取该字符串?

2 个答案:

答案 0 :(得分:1)

您可以从文件中读取的内容取决于文件中的内容。如果您将变量的名称写入文件,那么您也应该能够阅读它们。如果没有,那么你不能。但是,当您编写数据时,变量名称本身并不会写入文件。

确定用于将名称写入文件的技术。要阅读它们,只需执行反向操作即可。如果您以某种方式编写了分隔的数据,则读取直到遇到分隔符。如果您在名称前面加上字符长度,则读取长度,然后读取那么多字符。如果你没有使用可逆的技术编写名称,那么在继续阅读之前你必须改变你编写数据的方式。

你的问题是否可以阅读这些名字,答案是肯定的。您之后提出了另一个问题,即是否可以将从文件中读取的名称“转换”为具有相应名称的实际变量。答案是否定的。

普通变量没有RTTI; Delphi不维护程序中所有变量的名称。一旦编译器完成其工作,名称就不再存在于程序中。

获取变量的最简单方法是设置从字符串到设置值的映射。从文件中读取名称,在数据结构中查找名称,并使用相应的值。 TDictionary<string, sMinerals>对此非常适合。只需在程序启动时填充数据结构即可。

答案 1 :(得分:0)

非常简单...... 您需要将变量mineralwalkable保存为eBlockTypes的字符串表示形式。您将使用GetEnumName来执行此操作。 然后,您需要将eBlockTypes的字符串表示形式转换为实际的eBlockType,然后将其添加到mineralWalkable中。你将使用GetEnumValue来做到这一点。

以下示例显示了获取字符串表示形式...将其放置在一个集合中...然后将该集合...并将其移回字符串...

object Form54: TForm54
  Left = 0
  Top = 0
  Caption = 'Form54'
  ClientHeight = 290
  ClientWidth = 554
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  OnDestroy = FormDestroy
  PixelsPerInch = 96
  TextHeight = 13
  object Button1: TButton
    Left = 56
    Top = 160
    Width = 75
    Height = 25
    Caption = 'Button1'
    TabOrder = 0
    OnClick = Button1Click
  end
  object Edit1: TEdit
    Left = 56
    Top = 64
    Width = 265
    Height = 21
    TabOrder = 1
    Text = 'Edit1'
  end
  object cbType1: TCheckBox
    Left = 248
    Top = 91
    Width = 97
    Height = 17
    Caption = 'Type1'
    TabOrder = 2
  end
  object cbType2: TCheckBox
    Tag = 1
    Left = 248
    Top = 114
    Width = 97
    Height = 17
    Caption = 'Type2'
    TabOrder = 3
  end
  object cbType3: TCheckBox
    Tag = 2
    Left = 248
    Top = 137
    Width = 97
    Height = 17
    Caption = 'Type3'
    TabOrder = 4
  end
end

unit Unit54;
{Note the code assumes cbType1.Tag = 0, cbType2.Tag = 1, and cbType3.Tag = 2}
interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, TypInfo, IniFiles;

type
  TMyType = (mtOne, mtTwo, mtThree);
  TMyTypes=  set of TMyType;

  TForm54 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    cbType1: TCheckBox;
    cbType2: TCheckBox;
    cbType3: TCheckBox;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    private
    function getTypes1: TMyTypes;
    procedure setMyTypes1(const Value: TMyTypes);
    { Private declarations }

  public
    { Public declarations }
    property Types1: TMyTypes read getTypes1 write setMyTypes1;

    procedure SaveMyTypes(aVariableName: string; aMyTypes: TMyTypes);
    function ReadMyTypes(aVariableName: string): TMyTypes;
  end;

var
  Form54: TForm54;

implementation

{$R *.dfm}

procedure TForm54.Button1Click(Sender: TObject);
var
  a_MyTypes: TMyTypes;
  a_Str: string;
  a_Index: integer;
begin
  a_MyTypes := [];
  a_Str := '';
  Include(a_MyTypes,  TMyType(GetEnumValue(TypeInfo(TMyType), 'mtOne')));
  Include(a_MyTypes,  TMyType(GetEnumValue(TypeInfo(TMyType), 'mtTwo')));
//purpoesly have mtThree3 instead of mtThree
  Include(a_MyTypes,  TMyType(GetEnumValue(TypeInfo(TMyType), 'mtThree3')));
  for a_Index := Ord(Low(TMyType)) to Ord(High(TMyType)) do
    if TMyType(a_Index) in a_MyTypes then
      if a_Str = '' then
        a_Str := GetEnumName(TypeInfo(TMyType), a_Index)
      else
        a_Str := a_Str + ',' + GetEnumName(TypeInfo(TMyType), a_Index);
//should be mtOne, mtTwo
  Edit1.Text := a_Str;
end;

procedure TForm54.FormCreate(Sender: TObject);
begin
  Types1 := ReadMyTypes('Types1');
end;

procedure TForm54.FormDestroy(Sender: TObject);
begin
  SaveMyTypes('Types1', Types1);
end;

function TForm54.getTypes1: TMyTypes;
var
  a_Index: integer;
begin
  Result := [];
  for a_Index := 0 to Self.ComponentCount - 1 do
    if Self.Components[a_Index] is TCheckBox and (TCheckBox(Self.Components[a_Index]).Checked) then
      Include(Result, TMyType(Self.Components[a_Index].Tag));
end;

function TForm54.ReadMyTypes(aVariableName: string): TMyTypes;
var
  a_Ini: TIniFile;
  a_Var: string;
  a_List: TStrings;
  a_Index: integer;
begin
  Result := [];
  a_Ini := nil;
  a_List := nil;
  a_Ini := TIniFile.Create('MyType.ini');
  a_List := TStringList.Create;
  try
    a_Var := a_Ini.ReadString('Sets', aVariableName, '');
    a_List.Delimiter := ',';
    a_List.DelimitedText := a_Var;
    for a_Index := 0 to a_List.Count - 1 do
    begin
      Include(Result, TMyType(GetEnumValue(TypeInfo(TMyType), a_List[a_Index])));
    end;
  finally
    a_Ini.Free;
    a_List.Free;
  end;
end;

procedure TForm54.SaveMyTypes(aVariableName: string; aMyTypes: TMyTypes);
var
  a_Ini: TIniFile;
  a_Index: integer;
  a_Var: string;
begin
  a_Var := '';
  a_Ini := TIniFile.Create('MyType.ini');
  try
    for a_Index := Ord(Low(TMyType)) to Ord(High(TMyType)) do
      if TMyType(a_Index) in aMyTypes then
        if a_Var = '' then
          a_Var := GetEnumName(TypeInfo(TMyType), a_Index)
        else
          a_Var := a_Var + ',' + GetEnumName(TypeInfo(TMyType), a_Index);
    a_Ini.WriteString('Sets', aVariablename, a_Var);
  finally
    a_Ini.Free;
  end;
end;

procedure TForm54.setMyTypes1(const Value: TMyTypes);
var
  a_Index: integer;
begin
  for a_Index := 0 to Self.ComponentCount - 1 do
    if Self.Components[a_Index] is TCheckBox then
      TCheckBox(Self.Components[a_Index]).Checked := TMyType(TCheckBox(Self.Components[a_Index]).Tag) in Value;

end;

end.