3

したがって、テキストファイルを解析してキーと値のペアのリストのリスト返す メソッドがあり、返されたkvpsからオブジェクトを作成したい場合(kvpsの各リストは異なるオブジェクトを表します)、最良のメソッドは何でしょうか?

頭に浮かぶ最初の方法は非常に単純で、キーワードのリストを保持するだけです。

private const string NAME   = "name";
private const string PREFIX = "prefix";

上で定義した、必要な定数について取得したキーと照合します。これは私が取り組んでいるプロジェクトのかなりコアな部分ですが、うまくやりたいと思っています。誰かがもっと頑強な提案を持っていますか(上記の方法について本質的に頑健でないものがあると言っているわけではありません-私はただ尋ねています)?

編集:

詳細が求められています。私は暇なときに小さなゲームに取り組んでおり、構成ファイルを使用してゲームの世界を構築しています。4つあります。1つはすべてのクリーチャーを定義し、もう1つはすべてのエリア(およびマップ内のそれらの場所)を定義し、もう1つはすべてのオブジェクトを定義し、最後の1つはさまざまな構成オプションと他の場所に適合しないものを定義します。最初の3つの構成ファイルでは、ファイルの内容に基づいてオブジェクトを作成します。テキストが非常に多いため、名前、複数形、プレフィックスなどの文字列がたくさんあります。構成値はすべて次のようになります。

-
key: value 
key: value
-
key: value
key: value
-

ここで、「-」行は新しいセクション/オブジェクトを示します。

4

8 に答える 8

3

XmlSerializerを詳しく見てください。ディスク上でXMLを使用しないように制約されている場合でも、その機能の一部をコピーすることをお勧めします。これは次のようになります。

public class DataObject {
  [Column("name")]
  public string Name { get; set; }

  [Column("prefix")]
  public string Prefix { get; set; }
}

ただし、ファイルに何らかの形式バージョンを含めるように注意してください。そうしないと、次の形式変更が発生します。

于 2008-09-08T14:14:55.820 に答える
3

不当な仮定をたくさん行うと、キーと値のペアのリストを受け取り、適切なオブジェクトを返すファクトリを作成するか、無効な場合は例外をスローする(またはダミーオブジェクトを作成するなど)のが最善の方法だと思います。特定の場合により良い)。

private class Factory {

   public static IConfigurationObject Factory(List<string> keyValuePair) {

       switch (keyValuePair[0]) {

          case "x":
              return new x(keyValuePair[1]);
              break;
          /* etc. */
          default:
              throw new ArgumentException("Wrong parameter in the file");
       }

  }

}

ここでの最も強力な前提は、すべてのオブジェクトを部分的に同じように扱うことができる(つまり、同じインターフェイス(例ではIConfigurationObject)を実装するか、同じ継承ツリーに属する)ということです。

そうでない場合、それはあなたのプログラムフローとあなたがそれらで何をしているのかに依存します。しかし、それにもかかわらず、彼らはすべきです:)

編集:あなたの説明を考えると、ファイルタイプごとに1つのファクトリを持つことができます。そのスイッチは、ファイルタイプごとに許可されたタイプの信頼できるソースであり、おそらく共通点があります。リフレクションは可能ですが、これよりもわかりにくく自己文書化されているため、リスクが高くなります。

于 2008-09-08T14:20:17.290 に答える
2

何のためにオブジェクトが必要ですか?あなたがそれを説明する方法では、とにかくそれらをある種の(キーに関して)制限されたマップとして使用します。ある種の継承が必要ない場合は、マップのような構造を次のようなオブジェクトにラップするだけです。

[Javaに触発された擬似コード:]
class RestrictedKVDataStore {
   const ALLOWED_KEYS = new Collection('name', 'prefix');
   Map data = new Map();

   void put(String key, Object value) {
      if (ALLOWED_KEYS.contains(key))
          data.put(key, value)
   }

   Object get(String key) {
      return data.get(key);
   }
}
于 2008-09-08T14:16:00.077 に答える
1

編集:

それをスクラッチします、これはまだ当てはまります、しかし私はあなたがしていることは設定ファイルを読んでそれをこれに解析することだと思います:

List<List<KeyValuePair<String,String>>> itemConfig = 
    new List<List<KeyValuePair<String,String>>>();

この場合でも、リフレクションファクトリを使用してオブジェクトをインスタンス化できます。個々のキーと値のペアを渡す代わりに、ネストされた内部リストを渡すだけです。

古い投稿:

これは、リフレクションを使用してこれを行うための賢い小さな方法です。

基本的な考え方:

  • Objectクラスごとに共通の基本クラスを使用します。
  • これらのクラスをすべて独自のアセンブリに配置します。
  • この工場もそのアセンブリに入れてください。
  • 構成から読み取ったKeyValuePairを渡すと、KV.Keyに一致するクラスが検出され、KV.Valueでインスタンス化されます。
   
      パブリッククラスKeyValueToObjectFactory
      {{
         プライベート辞書_kvTypes=new Dictionary();

        public KeyValueToObjectFactory()
        {{
            //タイプを辞書にプリロードして、後で検索できるようにします
            //明らかに、オーバーヘッドを最小限に抑えるためにファクトリを再利用したいので、しないでください
            //ループで新しいファクトリをインスタンス化するような愚かなことをします。

            foreach(typeof(KeyValueToObjectFactory).Assembly.GetTypes()のタイプタイプ)
            {{
                if(type.IsSubclassOf(typeof(KVObjectBase)))
                {{
                    _kvTypes [type.Name.ToLower()]=タイプ;
                }
            }
        }

        public KVObjectBase CreateObjectFromKV(KeyValuePair kv)
        {{
            if(kv!= null)
            {{
                文字列kvName=kv.Key;

                //タイプ情報がディクショナリにある場合は、そのクラスの新しいインスタンスをインスタンス化します。
                タイプkvType;
                if(_kvTypes.TryGetValue(kvName、out kvType))
                {{
                    return(KVObjectBase)Activator.CreateInstance(kvType、kv.Value);
                }
                そうしないと
                {{
                    new ArgumentException( "Unrecognized KV Pair");をスローします。
                }
            }
            そうしないと
            {{
                nullを返します。
            }
        }
    }
于 2008-09-08T15:07:58.783 に答える
1

列名に一致するインターフェイスを作成してから、Reflection.Emit APIを使用して、フィールドのデータへのアクセスを許可するタイプを実行時に作成できます。

于 2008-09-08T14:08:05.760 に答える
0

@David:
私はすでにパーサーを持っています(そしてこれらのほとんどは手書きになるので、XMLに反対することにしました)。しかし、それは私がそれを行うための本当に素晴らしい方法のように見えます。私はそれをチェックする必要があります。バージョニングについても優れた点。

@Argelbargel:
それもよさそうだ。:')

于 2008-09-08T14:16:58.967 に答える
0

...これは私が取り組んでいるプロジェクトのかなりコアな部分ですが...

本当か?

それを単に抽象化し、後でリファクタリングすることを意図して基本的な実装を提供するのは魅力的です。

その後、重要なことであるゲームに取り掛かることができます。

ちょっとした考え

<bb />

于 2008-09-08T14:57:52.053 に答える
0

本当か?

はい; 私はこれを考え出しました。必要以上の仕事をするなんて、私には到底思えない。:')

于 2008-09-08T15:00:10.097 に答える