0

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

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

sMinerals = set of eBlockTypes; 

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

然后我有一个对象,它的字段之一是“sMinerals”。从文件加载对象属性时是否可以读取集合的“名称”?

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

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

所以我可以解析文件并读取除设置'mineralsWalkable'之外的所有属性。我知道我可以将该字符串与一些包含所有集合名称的 TStrings 进行比较,但问题是:是否可以通过以某种方式将字符串转换为变量来获取该集合?

4

2 回答 2

1

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

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

您的问题询问是否可以读取名称,答案是肯定的。您已经问过另一个问题,即是否可以将从文件中读取的名称“转换”为具有相应名称的实际变量。答案是否定的。

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

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

于 2013-07-16T03:17:00.127 回答
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.
于 2013-07-18T20:32:21.110 回答