今日、大量のデータを保持するために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
でも、new ExampleStruct()
が実際にExampleStruct()
を呼び出している場合と同じことが起こります。 ExampleStruct(int value = 1)
を呼び出さない。そのため、int
のデフォルト値である0をValue
として使用します。
さらに悪いことに、私の実際のコードは、_int value = 1
_パラメーターがコンストラクター内の有効な範囲内にあることを確認しています。これを上記のExampleStruct(int value = 1)
コンストラクターに追加します。
_if(value < 1 || value > 3)
{
throw new ArgumentException("Value is out of range");
}
_
したがって、現在のところ、デフォルトのコンストラクターは、必要なコンテキストでは無効なオブジェクトを実際に作成しました。誰もが私がどのようにできるか知っています:
ExampleStruct(int value = 1)
コンストラクターを呼び出します。ExampleStruct()
コンストラクターのデフォルト値の設定方法を変更します。また、Value
プロパティの代わりに次のようなフィールドを使用できることも認識しています。
_public readonly int Value;
_
しかし、私の哲学は、フィールドがconst
またはstatic
でない限り、フィールドを非公開で使用することです。
最後に、struct
の代わりにclass
を使用している理由は、これが単に可変でないデータを保持するオブジェクトであり、構築時と渡されたときに完全に入力する必要があるためです。パラメータとして、構造体が設計されている目的であるnull
(値によってstruct
として渡されるため)にすることはできません。
実際、MSDNにはstruct
に関するいくつかの優れたガイダンスがあります。
タイプのインスタンスが小さく、一般的に短命であるか、一般的に他のオブジェクトに埋め込まれている場合は、クラスの代わりに構造を定義することを検討してください。
タイプに次のすべての特性がない限り、構造を定義しないでください。
プリミティブ型(整数、倍精度など)と同様に、論理的に単一の値を表します。
インスタンスサイズが16バイト未満です。
それは不変です。
頻繁に箱詰めする必要はありません。
これらは考慮struct
の考慮事項であり、「これは常に構造体である必要がある」ではないことに注意してください。これは、struct
を使用するという選択は、パフォーマンスと使用法に影響を与える可能性があり(正と負の両方)、慎重に選択する必要があるためです。
特に、16バイトを超えるものにはstruct
を推奨していないことに注意してください(その場合、コピーのコストは参照のコピーよりも高くなります)。
さて、あなたの場合、これを行う良い方法は、デフォルト状態でstruct
を生成するファクトリを作成するか、プロパティで何らかのtrick
を実行して、最初の使用時に初期化するようにだます以外にありません。
struct
は、new X()
== default(X)
、つまり、新しく構築されたstruct
にそのstruct
のすべてのフィールドのデフォルト値が含まれるように機能することになっていることを忘れないでください。 C#ではnotでstruct
のパラメーターなしのコンストラクターを定義できるため、これは非常に明白ですが、警告なしにすべての引数をデフォルトにできるのは不思議です。
したがって、実際には、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;
}
}
ただし、絶対に必要な場合他の理由でstruct
が必要です-ただし、コピーキャストなどのstruct
のコストを考慮してください-できますこの:
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>
はnull
(つまり、HasValue == false
)になることに注意してください。したがって、これがtrueの場合、まだ設定しておらず、null合体演算子を使用して代わりに、デフォルトの1
。コンストラクターでdidを設定すると、null以外になり、代わりにその値を取得します...
struct
ExampleStruct
を次のようにするのは良い設計ではないと思います
_default(ExampleStruct)
_
つまり、すべてのインスタンスフィールドがゼロ/偽/ヌルである値はnot構造体の有効な値です。そしてあなたが知っているように、あなたが言うとき
_new ExampleStruct()
_
これはdefault(ExampleStruct)
とまったく同じであり、すべてのフィールド(自動プロパティから「生成された」フィールドを含む)がゼロである構造体の値を提供します。
多分あなたはこれを行うことができます:
_public struct ExampleStruct
{
readonly int valueMinusOne;
public int Value { get { return valueMinusOne + 1; } }
public ExampleStruct(int value)
{
valueMinusOne = value - 1;
}
}
_
コンパイラは実際には、ここで構造体の自動デフォルトctorを選択していると思います http://msdn.Microsoft.com/en-us/library/aa288208(v = vs.71).aspx ではなくデフォルト値でctorを使用します。
追加された参照: http://csharpindepth.com/Articles/General/Overloading.aspx (オプションのパラメーターセクション)
一部の言語(他に何もない場合はCIL)では、new T()
のフィールドが「すべてゼロ」のデフォルト、C#およびvb.net(およびおそらく他のほとんど)以外に設定されるように構造体コンストラクターを定義できます。言語)配列要素やクラスフィールドなどは常にdefault(T)
に初期化する必要があるため、new T()
と一致しないものに初期化することは混乱を招くと考えてください。 、構造体はnew T()
をdefault(T)
以外の意味で定義するべきではありません。
パラメータ化されたコンストラクタでデフォルトパラメータをジンクスするのではなく、目的のデフォルト値を返す静的構造体プロパティを定義し、出現するすべてのnew ExampleStruct()
を_ExampleStruct.NiceDefault;
_に置き換えることをお勧めします。
2015補遺
C#とVB.NETは、パラメーターのない構造体コンストラクターの定義の禁止を緩和する可能性があるようです。これにより、Dim s = New StructType()
のようなステートメントがs
にタイプStructType
の新しい配列アイテムに与えられた値とは異なる値を割り当てる可能性があります。 _new StructType
_は、C#のdefault(StructType)
に類似したものが存在する場合に適している場所でよく使用されるため、私はこの変更にそれほど熱心ではありません。 VB.NETは_Dim s As StructType = Nothing
_を許可しますが、それはかなりおかしなようです。
なぜpublic ExampleStruct(int value = 1) : this()
があるのですか?
public ExampleStruct(int value = 1)
であるべきではありませんか? :this()
はパラメーターなしのコンストラクターを作成していると思います。