6

大規模な計算を行うアプリケーションを C# で作成しています。すべてが基本的な構造体 - 値を中心に進んでいます。これは基本的に double で、いくつかの追加パラメータ (accuracy など) があります。構造体である必要があります。これは、作成されるパラメータが多すぎてヒープを割り当てることができないためです。ここで、それらがすべて正しく初期化されていることを確認する必要があります。デフォルトの明示的なコンストラクターを宣言することはできませんが、すべてを 0 で初期化するデフォルトのコンストラクターが提供されていますが、これは私のドメインでは意味がありません。

また、パラメーターを使用してコンストラクターを呼び出さずにインスタンスの作成を拒否する方法はありません...?

基本的に私が必要とするのは、このテストに合格することです:

[Test]
public void HowDoesThisStructureInitializeByDefault()
{
   Value v = new Value(); - if this did not compile - it would have been ok!

   Assert.AreEqual(0, v.Val); - passes
   Assert.AreEqual(-1, v.Accuracy); - fails
}

コンストラクターが明示的に呼び出されておらず、構造体がまだアクセスされていない場合は、例外をスローしても問題ありませんが、常にチェックすると時間がかかりすぎます。

私は今、ほとんど希望を失っています, 助けてください!

4

5 に答える 5

4

明示的なコンストラクターを定義できないのはなぜですか? これが彼らの目的です。さらに、なぜ「ヒープを割り当てる余裕がない」と思いますか? マネージ言語では、ヒープ割り当ては非常に安価です。ヒープを割り当てる余裕がない、またはそもそもヒープを割り当てるほうがコストがかかるという仮定をどのようにテストしましたか?

(「double と複数のパラメーター」で構成される型の場合、実際にはヒープ割り当てがより安価で効率的なサイズになっているのではないかと思います)

いずれにせよ、ユーザーが必要に応じて、値の型で既定のコンストラクターを呼び出すことを防ぐことはできません。できることは、デフォルト以外のコンストラクターなど、値を初期化するためのより良い方法が存在することを確認することです。何らかの理由でコンストラクターを作成できない場合は、呼び出されたときに値の型を作成して初期化する関数を作成します。

しかしもちろん、人々が実際にそれを呼び出すという保証はありません。

編集: .NET でのヒープ割り当ては、基本的に単純なスタック プッシュ操作のみで構成されます。これは、マネージド (およびガベージ コレクション) 言語の優れた点です。ランタイムは基本的に大きなスタックをヒープとして使用するため、割り当てごとにスタック ポインターが少しだけインクリメントされます (もちろん、十分な空きメモリがあることを確認した後)。ガベージ コレクターは、必要に応じてメモリの圧縮を処理します。

そのため、ヒープ割り当て自体はとてつもなく安価です。もちろん、追加の GC プレッシャーにより、再び速度が低下する可能性があります (ただし、私の知る限り、GC パスに必要な時間は、ライブ オブジェクトの数のみに依存し、GC されるオブジェクトには依存しないため、無数の"死んだ "オブジェクトが横たわっていても大きな問題ではないかもしれません) が、一方で、スタックの割り当ても自由ではありません。値の型は値によって渡されるため、型をパラメーターとして関数に渡すか、それを返すたびに、コピーを作成する必要があります。値の大きさはわかりませんが、double は 8 バイトです。追加のパラメーターがいくつかあることを考えると、32 バイトと仮定します。これは非常に大きいため、値型に余分なコピーが必要になるため、ヒープ割り当てを使用した場合よりも遅くなる可能性があります。多分。

ご覧のとおり、値型と参照型の両方に利点があります。あなたの場合、どちらが速いとは言えませんが、私があなただったら、この種の仮定を慎重に行うでしょう。可能であれば、参照型と値型の実装を切り替えて、どちらが最適かを確認できるようにコードを構成してください。または、小規模なテストを作成して、それぞれが大規模でどのように機能するかを予測しようとします。

于 2008-12-06T19:03:44.187 に答える
3

デフォルトのコンストラクターを取り除くことはできません (もちろん、Jon Skeet はWhy can't I define a default constructor for a struct in .NET?で非常によく答えています)。適切に初期化されたパラメーターを使用して構造体の値を定義します。モック/検証で単体テストを使用して、コードによって新しい値が作成されたときにファクトリを使用することを確認できます。これは、コンパイラが強制しないため、強制する必要がある規則です。

public static class StructFactory
{
    public static Value DefaultValue()
    {
         Value v = new Value();
         v.Value = 0.0;
         v.Accuracy = 15; /* digits */
         return v;
    }
}

...

Value v = StructFactory.DefaultValue();
于 2008-12-06T19:10:42.240 に答える
3

構造体フィールドはゼロ (またはヌル、または一般的なデフォルト (T)) に初期化されます。

Accuracy の初期値を -1 にする場合は、Accuracy プロパティを実装して、基になるフィールド == 0 の場合にプロパティが -1 を返すようにすることができます。

1 つの可能性:

struct Value
{
  int _accuracyPlusOne;

  public int Accuracy
  { 
    get { return _accuracyPlusOne - 1; }
    get { _accuracyPlusOne= value + 1; }
  }
}
于 2008-12-06T19:15:14.430 に答える
2

C# では、値型で既定のコンストラクターを作成できないと思います。あなたの問題に関連するいくつかの質問があります:

IL でそれを行う方法はありますが、配列を初期化してもこれらのコンストラクターは呼び出されません。

于 2008-12-06T19:01:54.503 に答える
0

デフォルトのコンストラクターで精度を -1 に初期化することを望んでいますか? 誰かが を使用するのを止めることはできないと思いますが、使用new Value()できるコンストラクターを追加して、必要new Value(10)な方法で精度を初期化することはできます。

[Struct Constructors]( http://msdn.microsoft.com/en-us/library/aa288208(VS.71).aspx)に関する MSDN ページを参照してください。

0 の精度に遭遇した場合 (その値が意味をなさない場合)、構造体を使用するコードで常に例外をスローできます。

于 2008-12-06T19:00:44.053 に答える