17

struct今日、大量のデータを保持するために を作成しているときに、この問題に遭遇しました。次に例を示します。

public struct ExampleStruct
{
    public int Value { get; private set; }

    public ExampleStruct(int value = 1)
        : this()
    {
        Value = value;
    }
}

元気でダンディに見えます。問題は、値を指定せずにこのコンストラクターを使用しようとし、パラメーターにデフォルト値の 1 を使用したい場合です。

private static void Main(string[] args)
{
    ExampleStruct example1 = new ExampleStruct();

    Console.WriteLine(example1.Value);
}

このコードは を出力し、出力0しません1。その理由は、すべての構造体にパラメーターのないパブリック コンストラクターがあるためです。したがって、 でthis()明示的なコンストラクターを呼び出す方法と同様に、が実際に呼び出しているが呼び出していないMain場所でも同じことが起こります。そのため、のデフォルト値 0 を として使用します。new ExampleStruct()ExampleStruct()ExampleStruct(int value = 1)intValue

さらに悪いことに、私の実際のコードは、int value = 1パラメーターがコンストラクター内の有効な範囲内にあるかどうかを確認しています。ExampleStruct(int value = 1)これを上記のコンストラクターに追加します。

if(value < 1 || value > 3)
{
    throw new ArgumentException("Value is out of range");
}

したがって、現状では、デフォルトのコンストラクターは、必要なコンテキストでは無効なオブジェクトを実際に作成しました。誰でも私ができる方法を知っています:

  • A.ExampleStruct(int value = 1)コンストラクターを呼び出します。
  • B.ExampleStruct()コンストラクターのデフォルト値の設定方法を変更します。
  • C. その他の提案/オプション。

また、Valueプロパティの代わりに次のようなフィールドを使用できることも承知しています。

public readonly int Value;

constしかし、私の哲学は、フィールドがまたはでない限り、非公開で使用することstaticです。

最後に、a のstruct代わりに aを使用している理由classは、これは変更不可能なデータを保持するための単なるオブジェクトであり、構築時に完全に入力する必要があり、パラメーターとして渡されたときにデータを入力できないようにする必要があるためですnull( )として値によって渡されますstruct。これは、構造体が設計されているものです。

4

5 に答える 5

29

実際、MSDN には、いくつかの優れたガイダンスがあります。struct

型のインスタンスが小さく、一般的に寿命が短い場合、または一般的に他のオブジェクトに埋め込まれている場合は、クラスではなく構造体を定義することを検討してください。

型が次の特性をすべて備えていない限り、構造体を定義しないでください。

プリミティブ型 (integer、double など) と同様に、単一の値を論理的に表します。

インスタンス サイズは 16 バイト未満です。

不変です。

頻繁に箱詰めする必要はありません。

これらは を考慮するための考慮事項であり、決して「これは常に構造体であるべき」ではないことに注意structください。これは、 を使用するという選択は、structパフォーマンスと使用法に (プラスとマイナスの両方の) 影響を与える可能性があり、慎重に選択する必要があるためです。

特に、16 バイトを超えるものは推奨されていないことに注意してくださいstruct(コピーのコストは、参照をコピーするよりも高くなります)。

さて、あなたの場合、デフォルト状態で を生成するファクトリを作成するか、プロパティでstruct何らかの操作を行って、最初の使用時に初期化するように騙す以外に、これを行う良い方法はありません。trick

aは==のstructように機能するはずです。つまり、新しく構築された a には、そのすべてのフィールドのデフォルト値が含まれます。C# ではa のパラメーターなしのコンストラクターを定義できないため、これは明らかですが、警告なしですべての引数を既定値にできるのは興味深いことです。 new X()default(X)structstructstruct

したがって、実際には a に固執しclassて不変にnullし、渡されるメソッドをチェックすることをお勧めします。

public class ExampleClass
{
    // have property expose the "default" if not yet set
    public int Value { get; private set; }

    // remove default, doesn't work
    public ExampleStruct(int value)
    {
        Value = value;
    }
}

ただし、他の理由でどうしても必要な場合は、コピーキャストなどのコストを考慮してください。次のようにします。structstruct

public struct ExampleStruct
{
    private int? _value;

    // have property expose the "default" if not yet set
    public int Value
    {
        get { return _value ?? 1; }
    }

    // remove default, doesn't work
    public ExampleStruct(int value)
        : this()
    {
        _value = value;
    }
}

デフォルトでは、は(つまり) にNullable<int>なることに注意してください。したがって、これが true の場合、まだ設定していないので、代わりに null 合体演算子を使用してデフォルトの of を返すことができます。コンストラクターで設定した場合、null ではなく、代わりにその値を取ります...nullHasValue == false1

于 2012-11-14T20:33:27.747 に答える
2

struct ExampleStructそのようなものを持っているのは良いデザインではないと思います

default(ExampleStruct)

つまり、すべてのインスタンスフィールドがゼロ/偽/ヌルである値は、構造体の有効な値ではありません。そしてあなたが知っているように、あなたが言うとき

new ExampleStruct()

これは、すべてのフィールド(自動プロパティから「生成された」フィールドを含む)がゼロである構造体の値とまったく同じでdefault(ExampleStruct)あり、その値を示します。

多分あなたはこれを行うことができます:

public struct ExampleStruct
{
  readonly int valueMinusOne;

  public int Value { get { return valueMinusOne + 1; } }

  public ExampleStruct(int value)
  {
    valueMinusOne = value - 1;
  }
}
于 2012-11-14T20:32:52.923 に答える
1

一部の言語(他に何もない場合はCIL)new T()では、フィールドが「すべてゼロ」のデフォルト以外に設定されるような構造体コンストラクターを定義できますが、C#とvb.net(およびおそらく他のほとんどの言語)は、配列要素やクラスフィールドなどは常にに初期化する必要がありdefault(T)、一致しないものに初期化するnew T()と混乱するため、構造体は。new T()以外のものを意味するように定義しないでくださいdefault(T)

パラメータ化されたコンストラクタでデフォルトパラメータをjinxしようとするのではなく、目的のデフォルト値を返す静的構造体プロパティを定義し、出現するすべての値new ExampleStruct()を。に置き換えることをお勧めしますExampleStruct.NiceDefault;

2015年補遺

C#とVB.NETは、パラメーターのない構造体コンストラクターの定義の禁止を緩和する可能性があるようです。これにより、タイプが新しい配列アイテムに与えられた値とは異なる値Dim s = New StructType()を割り当てるようなステートメントが発生する可能性があります。C#に類似したものが存在する場合にそれがより適切である場所で頻繁に使用されることを考えると、私はこの変更にそれほど熱心ではありません。VB.NETは許可しますが、それはかなり厄介なようです。sStructTypenew StructTypedefault(StructType)Dim s As StructType = Nothing

于 2012-11-14T22:08:39.343 に答える
1

コンパイラは実際に、デフォルト値で ctor を使用するのではなく、http: //msdn.microsoft.com/en-us/library/aa288208(v=vs.71).aspx で構造体の自動デフォルト ctor を選択していると思います。 .

追加の参照: http://csharpindepth.com/Articles/General/Overloading.aspx (オプションのパラメーター セクション)

于 2012-11-14T20:35:44.197 に答える
0

なぜあなたは持っていますpublic ExampleStruct(int value = 1) : this()か?

そうあるべきではないpublic ExampleStruct(int value = 1)ですか?:this()パラメータなしのコンストラクタを作成していると思います。

于 2012-11-14T20:40:19.037 に答える