2

読み取り専用のバッキングフィールドと、通常は解析を行うデフォルト以外のコンストラクターがある場合、TryParse パターンを使用して解析コンストラクターを一般的にどのように実装しますか?

以下は、私が話していることの不自然な例と、私が落ち着いたパターンですが、ぎこちないようです。実際には、いくつかの型には多数のプロパティがあります。確かに、n 個の ref 引数を取り、解析を行い、それらをそのように結び付けるメソッドを作成することはできますが、場合によっては 15 個の引数を持つメソッドを使用するのも面倒です。

2 つのコンストラクターのアイデアに加えて、try パースの結果をパース コンストラクターの読み取り専用フィールドにコピーする必要があるという考えには、少し匂いがします。

他の誰かがより良いパターンを持っていますか?

編集:さらにコンテキストを提供する

私がやろうとしているのは、大規模な (ish) コードベースをリファクタリングすることです。これには、コンストラクターに提供される文字列引数の解析がある、以下の例のような多くの型があります。現在、すべてのコードでコンストラクターの解析が使用されており、この解析のロジックはすべてコンストラクターで行われています。ぐちゃぐちゃで面倒。

最初にやりたいことは、このコードをコンストラクターからファクトリ メソッド (TryParse) に移動することですが、コンストラクターの署名を保持するため、コードベースに多くの変更はありません。長期的には、時間があればもっと良いことができます。

現在のところ、新しいコードで TryParse パターンを使用し、読み取り専用フィールドを保持しながら、既存のコードの構造署名をそのまま維持することが困難です。読み取り専用フィールドを緩和すれば、プロセス全体が簡単になりますが、そうはなりません。

public class Point
{
   private readonly float x, y;
   public float X { get { return x; } }
   public float Y { get { return y; } }

   public Point(string s)
   {
      Point result;

      if (TryParse(s, out result))
      {
         this.x = result.x;
         this.y = result.y;
      }
      else
      {
         throw new System.ArgumentException("cant parse");
      }
   }

   private Point(float x,float y) // for the sake of the example, this wouldnt have any use as public
   {
      this.x = x;
      this.y = y;
   }

   public static bool TryParse(string s,out Point result)
   {
      var numbers = s.Split(',');

      if(numbers.Length == 2)
      {
         result = new Point(float.Parse(numbers[0]),float.Parse(numbers[0]));
         return true;
      }
      else
      {
         result = null;
         return false;
      }
   }
}
4

2 に答える 2

5

現在のアプローチは実際には機能しませんfloat.Parse。例外がスローされる可能性があるためです。私は次のようなものを使用します:

public static bool TryParse(string s, out Point result)
{
   var numbers = s.Split(',');
   if (numbers.Length == 2)
   {
       float x, y;
       if (float.TryParse(numbers[0], out x) && 
           float.TryParse(numbers[1], out y))
       {
           result = new Point(x, y);
           return true;  
       }    
   }
   result = null;
   return false;
}

StriplingWarrior が言うように、まず構文解析コンストラクターを取り除きます。TryParseとにかく使用している場合は、Parseメソッドも追加します。

2 つのコンストラクターのアイデアに加えて、try パースの結果をパース コンストラクターの読み取り専用フィールドにコピーする必要があるという考えには、少し匂いがします。

このアプローチでは、必要なコンストラクターは 1 つだけですが、をコンストラクターに渡してオブジェクトにコピーすることの何が問題になっているのでしょうか? それは私には自然に思えます。

または、 Noda Timeで使用しているアプローチを使用して、解析とフォーマットを担当する完全に別のオブジェクトを作成し、解析ParseResult<T>の成功/失敗を表すことができる型を使用して、例外をスローする機能を保持することもできます。障害に関する重要な情報。個人的には、BCL パターンよりもはるかに優れていると思いますが、間違いなく私は偏っています :)

于 2012-07-30T20:51:58.677 に答える
4

私は通常、コンストラクターの解析を避けようとします。コンストラクターはできる限り何もしないで、通常は後で使用するためにフィールドに直接格納される引数のみを取るべきであるという一般的な意見があります。文字列を解析したい場合、それはコンストラクターの責任ではありません。

TryParseC#/.NET アプリの典型的な予想パターンに従うメソッドがあります。Jon Skeet が推奨する変更を行い、ユーザーが astringを aに解析したい場合は、そのメソッドを直接呼び出すことを期待してくださいPoint

于 2012-07-30T20:51:24.417 に答える