Delphi 将字符串转换为集合类型

Delphi 将字符串转换为集合类型,delphi,fpc,Delphi,Fpc,在我的应用程序中,我定义了许多集合: eBlockTypes = (btNone,btUndefined,btStone, btYellowFlower, btWoodBrown...); sMinerals = set of eBlockTypes; var mineralsRare: sMinerals; mineralsPlants: sMinerals; mineralsAll: sMinerals; mineralsDeep: sMinerals; miner

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

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
因此,我可以解析该文件并读取除“可转换”集之外的所有属性。
我知道我可以将该字符串与包含所有集合名称的一些tstring进行比较,但问题是:是否可以通过某种方式将字符串转换为变量来获取集合?

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

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

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

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

获取变量的最简单方法是设置从字符串到设置值的映射。从文件中读取名称,在数据结构中查找名称,并使用相应的值。一个
t字典
将是最好的选择。只要在程序启动时填充数据结构即可。

非常简单。。。 您需要将变量SILLAKABLE保存为eBlockTypes的字符串表示形式。您将使用GetEnumName来完成此操作。 然后需要将eBlockTypes的字符串表示形式转换为实际的eBlockTypes,然后将其添加到Swalkable中。您将使用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.

当然,这是可能的。但是,在我们告诉您如何做之前,您需要提供一个更清晰的说明。这些应该有助于解决您的问题…还有一个非常简单的case语句。从我所读的内容来看,它们可以将字符串转换为set的元素,但不能转换为set的“type”,我是“手工”编写的:P对象是预定义的,不需要保存。所以它是一个变量名。我知道typeinfo可以将集合元素转换为字符串并返回,但我不知道如何使用“set”类型变量而不是元素来实现这一点可能是您手工编写的,但这不是我的重点。你写这封信的方式使它可以被阅读;在本例中,它位于一行上,前面有一个看起来像固定的、已知的标题。因此,查找标题,然后一直读到下一个换行符,就有了字符串。我不明白你为什么会怀疑自己一开始就能读懂这个名字。好吧,我编辑了这个问题,让它更清楚,并用“否”作为答案。这仍然会将集合元素从字符串转换回来。我不想在文件中列出元素,因为文件中有很多元素,并且集合被用作分组方法,正是出于这个原因,我不明白您想要在文件中显示什么…您要么保存变量的值…变量本身没有任何意义…这意味着矿化迁移=btStone,btYellowFlower。因此,您将该字符串表示形式保存在文件中。查看类型后…看起来像另一个MineCraft;)集合分组块类型在代码中定义。如果我在解析对象文件时加载集合的元素,那么它将一直工作,直到矿化迁移定义被更改(添加了新类型的块),所以它忽略了要点。想知道我是否可以像使用枚举名一样转换集合名。不要介意,我只是想知道这是否可能,但如果不可能,那么这不是一个大问题。一个变量…所有的集合都是…它除了说…这些元素都在这个集合中之外没有其他意义…如果你只需要能够从字符串名到实际的集合变量…然后创建一个函数,使用字符串名并返回正确的值如果集合是常量并在代码中定义,则设置变量。