Delphi应用程序配置的最佳方法是什么? [英] What is the best way to serialize Delphi application configuration?

查看:136
本文介绍了Delphi应用程序配置的最佳方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我会自己回答这个问题,但如果你比我快,或者不喜欢我的解决方案,请随时提供你的答案。我只是想出了这个想法,并希望对此有一些看法。



目标:可读的配置类(如INI文件),但无需编写(并在添加新配置项后调整)加载和保存方法。



我想创建一个类,如

  TMyConfiguration = class(TConfiguration)
...
属性ShowFlags:Boolean读取FShowFlags写入FShowFlags;
属性NumFlags:整数读取FNumFlags写入FNumFlags;
结束

调用TMyConfiguration.Save(继承自TConfiguration)应该创建一个像

  [选项] 
ShowFlags = 1
NumFlags = 42

问题:最好的方法是什么?

解决方案

这是我提出的解决方案。



我有一个基础课程

  TConfiguration = class 
protected
type
TCustomSaveMethod = function(Self:TObject; P:Pointer):String;
TCustomLoadMethod = procedure(Self:TObject; const Str:String);
public
程序保存(const FileName:String);
程序加载(const FileName:String);
结束

加载方法看起来像这样(相应地保存方法):

 程序TConfiguration.Load(const FileName:String); 
const
PropNotFound ='_PROP_NOT_FOUND_';
var
IniFile:TIniFile;
计数:整数;
列表:PPropList;
TypeName,PropName,InputString,MethodName:String;
LoadMethod:TCustomLoadMethod;
begin
IniFile:= TIniFile.Create(FileName);
try
计数:= GetPropList(Self.ClassInfo,tkProperties,nil);
GetMem(List,Count * SizeOf(PPropInfo));
try
GetPropList(Self.ClassInfo,tkProperties,List);
for I:= 0 to Count-1 do
begin
TypeName:= String(List [I] ^。PropType ^ .Name);
PropName:= String(List [I] ^。Name);
InputString:= IniFile.ReadString('Options',PropName,PropNotFound);
if(InputString = PropNotFound)then
继续;
MethodName:='Load'+ TypeName;
LoadMethod:= Self.MethodAddress(MethodName);
如果没有分配(LoadMethod)然后
raise EConfigLoadError.Create('自定义类型的无负载方法'+ TypeName);
LoadMethod(Self,InputString);
结束
finally
FreeMem(List,Count * SizeOf(PPropInfo));
结束
finally
FreeAndNil(IniFile);
结束

基类可以为delphi默认类型提供加载和保存方法。然后,我可以为我的应用程序创建一个配置:

  TMyConfiguration = class(TConfiguration)
...
发布
函数SaveTObject(P:指针):String;
程序LoadTObject(const Str:String);
发布
属性BoolOption:Boolean读取FBoolOption写入FBoolOption;
属性ObjOption:TObject读取FObjOption写入FObjOption;
结束

自定义保存方法的示例:

  function TMyConfiguration.SaveTObject(P:Pointer):String; 
var
Obj:TObject;
begin
Obj:= TObject(P);
结果:= Obj.ClassName; //没有意义唯一的例子
结束


I will answer this question myself, but feel free to provide your answers if you are faster than me or if you don't like my solution. I just came up with this idea and would like to have some opinions on that.

Goal: a configuration class that is readable (like an INI-file) but without having to write (and adapt after a new configuration item has been added) the load and save methods.

I want to create a class like

TMyConfiguration = class (TConfiguration)
  ...
  property ShowFlags : Boolean read FShowFlags write FShowFlags;
  property NumFlags : Integer read FNumFlags write FNumFlags;
end;

Calling TMyConfiguration.Save (inherited from TConfiguration) should create a file like

[Options]
ShowFlags=1
NumFlags=42

Question: What is the best way to do this?

解决方案

This is my proposed solution.

I have a base class

TConfiguration = class
protected
  type
    TCustomSaveMethod = function  (Self : TObject; P : Pointer) : String;
    TCustomLoadMethod = procedure (Self : TObject; const Str : String);
public
  procedure Save (const FileName : String);
  procedure Load (const FileName : String);
end;

The Load methods look like this (Save method accordingly):

procedure TConfiguration.Load (const FileName : String);
const
  PropNotFound = '_PROP_NOT_FOUND_';
var
  IniFile : TIniFile;
  Count : Integer;
  List : PPropList;
  TypeName, PropName, InputString, MethodName : String;
  LoadMethod : TCustomLoadMethod;
begin
  IniFile := TIniFile.Create (FileName);
  try
    Count := GetPropList (Self.ClassInfo, tkProperties, nil) ;
    GetMem (List, Count * SizeOf (PPropInfo)) ;
    try
      GetPropList (Self.ClassInfo, tkProperties, List);
      for I := 0 to Count-1 do
        begin
        TypeName  := String (List [I]^.PropType^.Name);
        PropName  := String (List [I]^.Name);
        InputString := IniFile.ReadString ('Options', PropName, PropNotFound);
        if (InputString = PropNotFound) then
          Continue;
        MethodName := 'Load' + TypeName;
        LoadMethod := Self.MethodAddress (MethodName);
        if not Assigned (LoadMethod) then
          raise EConfigLoadError.Create ('No load method for custom type ' + TypeName);
        LoadMethod (Self, InputString);
        end;
    finally
      FreeMem (List, Count * SizeOf (PPropInfo));
    end;
  finally
    FreeAndNil (IniFile);
  end;

The base class could provide load and save methods for the delphi default types. I can then create a configuration for my application like this:

TMyConfiguration = class (TConfiguration)
...
published
  function  SaveTObject (P : Pointer) : String;
  procedure LoadTObject (const Str : String);
published
  property BoolOption : Boolean read FBoolOption write FBoolOption;
  property ObjOption : TObject read FObjOption write FObjOption;
end;

Example of a custom save method:

function TMyConfiguration.SaveTObject (P : Pointer) : String;
var
  Obj : TObject;
begin
  Obj := TObject (P);
  Result := Obj.ClassName;  // does not make sense; only example;
end;       

这篇关于Delphi应用程序配置的最佳方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆