2

私のコードでは、次のパターンが一般的です。クラスには複数のコンストラクターがあります。1 つは「指定されたコンストラクター」で、その他は便宜上のものです。コードは次のようになります。

class Foo 
{
  Foo(int bar, string baz) 
  {
    this.Bar = bar;
    this.Baz = baz;
  }

  Foo()
    : this(0, "Empty baz")
  {
  }

  Foo(Foo f)
    : this(f.Bar, f.Baz)
  {
  }

  int Bar {get;set;}
  string Baz {get;set;}
}

を呼び出すパラメーターなしのコンストラクターの場合this(...)、これは正常に機能します。ただし、誰かがnull引数としてコピー コンストラクターに渡すとFoo(Foo)、式により、結果は null 参照例外になりますf.Bar。代わりに ArgumentNullException を確認したいので、通常、このような場合はパターンから外れて、コンストラクターを「手動で」実装します。これにより、コードが重複します。これを回避するエレガントな方法はありますか?つまり、指定されたコンストラクターを1つ持ち、他のコンストラクターのパラメーター検証を実行しますか?

編集済み:この例は、問題を説明するためだけの必要最小限のものです。実際の例では、より複雑な引数検証ロジックと初期化コードがあります。

4

3 に答える 3

2

これは次のように確認できます。

class Foo
{
    private static Foo ThrowIfNull(Foo foo)
    {
        if (foo == null) throw new ArgumentNullException("foo");
        return foo;
    }

    ...

    Foo(Foo f) : this (ThrowIfNull(f).Bar, f.Baz)
    {
    }
}

スタック トレースが少し失われますが、それほど多くはありません。

于 2012-07-17T10:41:02.677 に答える
1

クラススコープの外から取得したパラメータを常にチェックする必要があります。

于 2012-07-17T10:34:01.087 に答える
0

このコードを変換できませんでした: (?)

  Foo(Foo f)
  {
       if(f != null) 
       {
            Bar = f.Bar;
            Baz = f.Baz;
       }
       else
       {
           throw new ArgumentNullException("f");
       }
  }

正直なところ、これがあなたの場合に進むべき道だと思います。なぜ物事を過度に複雑にするのですか?

構築時にいくつかのプロパティを設定しようとしており、これをコンストラクター自体に実装できます。1 つ、2 つ、または 3 つの行を避けたいので、車輪を発明しようとしています。;)

オプションB・・・アップデート!!

別のアプローチがあります。ユースケースをカバーするがオプションのパラメーターを使用する単一のコンストラクターはどうですか?

コンストラクタは次のようになります。

Foo(int bar = -1, string baz = null, Foo f = null) 
  {
    if(bar >= 0 && !string.IsNullOrEmpty(baz)) 
    {
       Bar = bar;
       Baz = baz;
    }
    else if(f != null) 
    {
       Bar = f.Bar;
       Baz = f.Baz;
    }
    else
    {
        Bar = 0;
        Baz = "Empty baz";
    }
  }

このコンストラクターを呼び出す方法に応じて、さまざまな処理が行われます。

于 2012-07-17T10:41:21.483 に答える