2009-08-18 15 views
10

私はこの質問に自分自身で答えるつもりですが、あなたが私よりも速く、私の解決策が気に入らなければ、答えを提供してください。私はちょうどこのアイデアを考え出し、それについていくつか意見を述べたいと思います。Delphiアプリケーションの設定をシリアル化する最善の方法は何ですか?

目標:(INIファイルのような)が、書き込み(および新しい設定項目が追加された後に適応)負荷とメソッドを保存することなく読み取り可能なコンフィギュレーションクラス。行うための最善の方法は何:

は私が

[Options] 
ShowFlags=1 
NumFlags=42 

質問のようにファイルを作成する必要があります(TConfigurationから継承)TMyConfiguration.Saveを呼び出す

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

のようなクラスを作成したいですこの?

答えて

7

これは私が提案した解決策です。

は、私は、基本クラスに持って

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; 

方法は(従ってSaveメソッド)のようになりロード:

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; 

基底クラスは、負荷を提供し、デルファイ・デフォルト・タイプのための方法を救うことができます。私は、このように私のアプリケーションの構成を作成することができます保存方法カスタムの

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; 

例:

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

これは私にとっては大丈夫です。もっとスマートな解決策があると思いますか? –

+0

@Jeroen:私がここで尋ねるときのほとんどの場合、私はスマートなコメント、改善と批判の提案をたくさん得ている経験:それに加えて、他の人が潜在的に利益を得ることができるようにそのコードを共有したい。 – jpfollenius

0

これは、Javaのためになります。

私はjava.util.Propertiesクラスを設定ファイルまたはプロパティファイルで読み込むのが好きです。私が気に入っているのは、上に示したのと同じように(key = value)、ファイルを行に並べることです。 また、多くのスクリプト言語のような、コメントの行に#(シャープ記号)を使用しています。

ですから、使用することができます

Properties props = new Properties(); 
props.load(new FileInputStream(PROPERTIES_FILENAME)); 
String value = props.getProperty("ShowFlags"); 
boolean showFlags = Boolean.parseBoolean(value); 

と簡単:

ShowFlags=true 
# this line is a comment  
NumFlags=42 

など

次に、あなただけのようなコードを持っています。

+0

私がDelphiを要求して以来、多くの助けにはなりません。あなたが提案するクラスはJava固有のものです... – jpfollenius

+0

それについては申し訳ありません。あなたは実際に指定していないので、私はそれを撃った。質問は非常に一般的でした。あなたのdelphiタグが見えませんでした。 – Nick

+0

問題ありません。とにかくありがとう。 – jpfollenius

1

基本的には、指定されたオブジェクト(場合によってはiniファイルへの設定)をシリアル化するソリューションを求めています。そのための準備が整ったコンポーネントがあり、あなたはherehereと見ることができます。

6

私は構成の手段として私のすべてのアプリケーションにXMLを使用しています。これは、次のとおりです。

  • 柔軟
  • 将来の機能の証拠
  • 任意のテキストリーダーアプリケーションに拡張することは非常に簡単
  • で読みやすいです。クラスを変更する必要はありません

私はXMLライブラリを使用して、値の欠落を監視する必要もなく、設定の読み取りや変更が非常に簡単です。また、XMLをクラス内のアプリケーションにマップすることで、速度が問題になる場合や、一定の値が常に読み取られる場合に、より高速にアクセスすることができます。

私ははるかに少ないオプションの他の設定方法を見つける:

  • INIファイル:なし深さの構造、はるかに少ない柔軟
  • レジストリ:ちょうどそれから遠ざけます。
+1

私も同じことをしますが、DelphiのXMLデータバインディングウィザードを使用してファイルをオブジェクトにマップします。 –

+1

事は:誰もがXMLを理解できるわけではないが、INIファイルはユーザーが簡単に理解できると思う。私はそのための設定ダイアログが必要であることを知っていますが、私は誰もがXMLにダイビングすることなく、より高度な設定を変更できるようにしたいと思います。 – jpfollenius

+1

XMLファイルは本当に読みやすいです。私はここで基本的なXMLについて話しています。属性と値(テキスト)を持つノードだけ。 INIに比べてほとんど読みにくくありません。さて、あなたはタグに "ボイラーメッキ"をもっと持っています。しかし、あなたがユーザーを変更することを心配する場合は、GUIを作成してください。ユーザーがファイルを独自に変更することはできません。 INI。 – Runner

3

私の好ましい方法は、私のグローバルインタフェースユニットのインターフェイスを作成することです:

type 
    IConfiguration = interface 
    ['{95F70366-19D4-4B45-AEB9-8E1B74697AEA}'] 
    procedure SetConfigValue(const Section, Name,Value:String); 
    function GetConfigValue(const Section, Name:string):string; 
    end; 

このインタフェースは、その後、私のメインフォームで「公開」されています

type 
    tMainForm = class(TForm,IConfiguration) 
    ... 
    end; 

ほとんどの時間実際の実装はメインフォームではなく、単にプレースホルダーであり、インターフェイスをメインフォームが所有する別のオブジェクトにリダイレクトするためにimplementsキーワードを使用します。これのポイントは、構成の責任が委任されていることです。各ユニットは、設定がテーブル、iniファイル、xmlファイル、またはレジストリに格納されているかどうかは気にしません。これは私が世界的なインターフェースユニットを使用する任意の単位で行うことができDOESすると、次のような呼び出しを行います:

var 
    Config : IConfiguration; 
    Value : string; 
begin 
    if Supports(Application.MainForm,IConfiguration,Config) then 
    value := Config.GetConfiguration('section','name'); 
    ...  
end; 

必要とされるすべては、私が働いているユニットに形成し、私のグローバルインターフェースユニットを追加していますに。また、メインフォームを使用しないため、後で別のプロジェクトに再利用することにした場合、これ以上変更する必要はありません。構成の格納方式が完全に異なっていても機能します。

私の一般的な好みは、テーブル(データベースアプリケーションを扱っている場合)またはXMLファイルを作成することです。マルチユーザーデータベースアプリケーションの場合は、2つのテーブルを作成します。 1つはグローバル構成用、もう1つはユーザー構成用です。

+0

+1、私はあなたが書いたもののほとんどに同意しています。違いは主にスタイルの問題です。しかし、その答えは、私が理解している質問とはあまり関係がありません。「子孫の変更を必要とせずに、永続的な記憶域に自身をロードして格納できる基本クラスを作成する最良の方法は何ですか?クラス"。それは少なくともOPが答えた質問です、タイトルはちょうど質問のテキストと一致しません。それでも、INIファイルソリューションをハードコーディングするのではなく、あなたの助言に従ってください。 – mghie

+0

すべてのアプリケーションで繰り返されるため、設定のセットアップに必要な時間がかかりません。私はあなたのアプローチがある程度好きですが、それは私には十分なKISSではありません。 XMLバックエンドとそれにアクセスするための良いインタフェースを持つシンプルなグローバルシングルトンは、ほとんどの場合十分です。小さなシンプルなアプリケーションには十分です。 完全なデータベース指向のアプリケーションでも、そのデータにアクセスするための単純な設定ファイルが必要です:) – Runner

+0

mghieさんのコメントにもっと同意できませんでした。あなたは、インターフェイスとデリゲートを使ってグローバル変数に代わる素晴らしい方法を提案しますが、シリアライゼーションの実行方法については何も言いません。私のソリューションからIPropertyStorerを抽出して、具体的な実装(INIファイル/ XML /データベース)と構成を分離することは問題ありません。しかし、最小限の労力で永続ストレージに関するポイントを変更することはありません。 – jpfollenius

1

いつか私は同じタスクのために小さな単位を書きました - アプリケーションの設定をxml-fileに保存/ロードするため。

私たちのフリーウェアSMComponentライブラリにObj2XML.pas単位を確認します(Javaのプロパティを使用して) http://www.scalabium.com/download/smcmpnt.zip

0

ニックスの答えは、ポイントを持っています。アプリケーションの部品間の周りの設定を読んで、合格するには、この単純な方法は導入しません特別な構成クラスの依存関係シンプルなキー/値リストを使用すると、アプリケーションモジュール間の依存関係を減らし、コードの再利用を容易にすることができます。

Delphiでは、単純なTStringsベースのコンフィグレーションがコンフィグレーションを実装する簡単な方法です。例:

mail.smtp.host=192.168.10.8  
mail.smtp.user=joe  
mail.smtp.pass=******* 
関連する問題