0

これは構造体の良い候補ですか?

コンストラクターが入力を検証し、検証されたデータを単一の「ルーティングコード」として格納する、この不変の構造体の例を考えてみます。

struct RoutingCode
{
  private readonly string routingCode;

  RoutingCode(string prefix, string service, string sender)
  {
    // Validate prefix, service, sender strings
    // ...

    if (isInvalid) throw ArgumentException();

    // 
    this.routingCode = prefix + service + sender;
  }

  // Gets the validated routing code.
  public string Routing
  {
    return this.routingCode;
  }

  public int RoutingLength
  {
    return this.routingCode.Length;
  }
}

この簡略化された例は、 :のstruct代わりに使用するのに適した候補であるように思われます。class

  • 不変です。
  • 特異値を表します。
  • インスタンスサイズが小さい。

問題は、すべての構造体に暗黙のデフォルトコンストラクターがあることです。この例では、デフォルトのコンストラクターは、プロパティが返さRoutingCode()れるオブジェクトをインスタンス化します。これは無効なルーティングコードです。これは、バッキングフィールドにデフォルトインスタンスの非常に論理的で有効な「ゼロ」が含まれているなどの他の構造体とは異なります。RoutingnullPointBigInteger

有効なルーティングコードを保証しないことに加えて、プロパティはデフォルトのインスタンスで呼び出された場合にaRoutingLengthをスローします。NullReferenceException

これを維持するための議論とstructそれを作るための議論は何classですか?

4

2 に答える 2

2

デフォルト値の問題は簡単に解決できます。

struct RoutingCode
{
  private readonly string routingCode;    
  RoutingCode(string prefix, string service, string sender)
  {
    // Validate prefix, service, sender strings
    // ...
    if (isInvalid) throw ArgumentException();
    this.routingCode = prefix + service + sender;
  }

  public string IsValid 
  {
    get { return this.routingCode != null; }
  }

  // Gets the validated routing code.
  public string Routing
  {
    get { return this.routingCode; }
  }

  public int RoutingLength
  {
    get { return this.routingCode == null ? 0 : this.routingCode.Length; }
  }
}

OK、これでどのプロパティも例外をスローせず、値が無効かどうかを判断する方法があります。当面の問題は、これが構造体の適切な候補であるかどうかです。あなたはそれが(1)不変であり、(2)小さく、そして(3)論理的に値であるということは正しいです。無効な値を表すことができるという事実を受け入れたいのであれば、これはおそらく構造体の良い候補です。

しかし、より良い質問は次のとおりです。これがクラスにならない正当な理由はありますか?それを構造体にすることへの異議を探すのではなく、それをクラスにすることへの異議を探してください。

于 2013-03-18T04:23:26.607 に答える
0

非表示フィールド構造体は、初期化されていないインスタンスが特定の目的の値を保持しているかのように動作する可能性があります[デフォルト値は、特定のタイプの初期化されていないすべてのインスタンスで同じである必要があります]。各プロパティアクセサーまたはメソッドに、タイプがシステムのデフォルト値を保持しているかどうかを確認させ、保持している場合は、代わりに目的のデフォルト値に置き換えます。

コードがインスタンスを作成できるようにしたい場合、そのようなインスタンスがデフォルト値であると想定しない場合Routingは、型に新しいGUID(または表示されない他の何か)に等しい静的文字列を宣言させることができます。他の場所)、コンストラクターとメソッドを変更します。nullRoutingget

static string stringRepresentingNull = Guid.NewGuid().ToString();

RoutingCode(string wholeString)
{
  if (wholeString == null) 
    wholeString = stringRepresentingNull;
  this.routingCode = wholeString;
}

public string Routing
{
  get { 
    if (this.routingCode == null) 
      return "12-3456-789"; // Default routing string
    else if (Object.ReferenceEquals(routingCode,stringRepresentingNull)
      return null;
    else
      return routingCode;
}

外部コードが何らかの方法で型に関連付けられているGUIDを推測できたとしても、外部コードがReferenceEqualsに一致する文字列を生成する方法はないことに注意してくださいstringRepresentingNull

同様に、デフォルト値が123のプロパティが必要な場合は、プロパティgetterのyieldをint格納して取得できます。backingField=(desiredValue ^ 123)backingField ^ 123

null型が構造体であるかクラスであるかという問題は、主に、型のデフォルト値を、または有効な値として動作させるかどうかの1つに要約されます。nullのデフォルトが必要な場合は、クラスを使用します。有効なデフォルトが必要な場合は、構造体を使用してください。

于 2013-12-20T23:01:01.217 に答える