2019年6月2日のManjulata Yadavのブログ投稿「構造体とC#のクラスの違い」から翻訳され、いくつかのコンテンツと例が追加されています。
構造体(struct
)はclass
、クラス()の軽量バージョンです。構造体は値型であり、組み込み型のように動作するオブジェクトを作成するために使用できます。
比較する
構造とクラスには多くの特徴がありますが、クラスと比較して次のような制限があります。
-
構造体にデフォルトのコンストラクター(パラメーターなしのコンストラクター)またはデストラクタを含めることはできません。また、すべてのフィールドにコンストラクターで値を割り当てる必要があります。
public struct Coords { public double x; public double y; public Coords() //错误,不允许无参构造函数 { this.x = 3; this.y = 4; } public Coords(double x) //错误,构造函数中必须给所有字段赋值 { this.x = x; } public Coords(double x) //这个是正确的 { this.x = x; this.y = 4; } public Coords(double x, double y) //这个是正确的 { this.x = x; this.y = y; } }
-
構造は値型であり、割り当て時にコピーされます。
-
構造体は値型であり、クラスは参照型です。
-
構造体は、
new
ケース演算子をインスタンス化せずに使用できます。
例えば:public struct Coords { public double x; public double y; } static void Main() { Coords p; p.x = 3; p.y = 4; Console.WriteLine($"({p.x}, {p.y})"); // 输出: (3, 4) }
-
構造体は別の構造体またはクラスから継承できず、クラスは構造体を継承できません。全ての構造は、直接、抽象クラスから継承され
System.ValueType
、System.ValueType
そしてそれから継承されましたSystem.Object
。 -
構造体は基本クラスであるため、構造体
abstract
ではありません。また、シールは常に暗黙的です(sealed
)。 -
抽象化は(構造体に対して
abstract
)許可されておらず、シール(sealed
)修飾子は構造体メンバーprotected
またはprotected internal
修飾子の使用を許可されていません。 -
関数メンバーの構造体を抽象(
abstract
)または仮想(virtual
)にすることはできません。書き換え(override
)は、System.ValueType
継承されたメソッドからの修飾子の書き換えのみを許可します。 -
インスタンスの属性またはフィールドに、構造体に初期化子を含めることはできません。ただし、この構造では、静的プロパティまたはフィールドに初期化子を含めることができます。
例えば:public struct Coords { public double x = 4; //错误, 结构体中初始化器不允许实例字段设定初始值 public static double y = 5; // 正确 public static double z { get; set; } = 6; // 正确 }
-
構造体はインターフェースを実装できます。
-
構造を使用できます
nullable type
(つまりNullable<T>
、inT
)、割り当てられたnull
値、参照[Nullable<T> Struct
]
構造体またはクラスをいつ使用するのですか?
この質問に答えるには、それらの違いをよく理解する必要があります。
シリアルナンバー | 構造(struct ) |
Class(class ) |
---|---|---|
1 | 構造体は値型であり、スタック(stack )に割り当てることも、包含型にインラインで割り当てることもできます。 |
このクラスは参照型であり、ヒープ(heap )に割り当てられ、ガベージコレクションされます。 |
2 | 値型の割り当てと解放は、通常、参照型の割り当てと解放よりも費用効果が高くなります。 | 大きな参照型の割り当ては、大きな値型の割り当てよりも安価です。 |
3 | 構造では、各変数は、(データの独自のコピーが含まれているref し、out パラメータ変数を除く)、変数の操作は、他に影響を与えません。 |
クラスでは、2つの変数に同じオブジェクトへの参照を含めることができ、一方の変数に対する操作は、もう一方の変数に影響します。 |
このように、構造(struct
)は次の状況でのみ使用できます。
- これは、ベースのタイプ(論理的
int
になど)などの単一の値を表しdouble
ます。 - それは不変です。
- 頻繁に箱に入れられたり、箱から出されたりすることはありません。
それ以外の場合はすべて、型をクラス(class
)として定義する必要があります。
構造例:
struct Location
{
public int x, y;
public Location(int x, int y)
{
this.x = x;
this.y = y;
}
}
static void Main()
{
Location a = new Location(20, 20);
Location b = a;
a.x = 100;
Console.WriteLine(b.x);
}
出力は20になります。「b」の値は「a」のコピーであるため、「b」は「ax」の変更による影響を受けません。ただし、クラスでは、変数「a」と「b」が同じオブジェクトを参照しているため、出力は100になります。
以下は翻訳者の補足です
構造体インスタンスとクラスインスタンス
構造体インスタンスのメモリはスタック(stack
)に割り当てられ、占有されたメモリは、それが宣言されたタイプまたはメソッドとともに再利用されます。これが、割り当てるときに構造をコピーする理由の1つです。対照的に、クラスインスタンスのメモリはヒープ(heap
)に割り当てられます。クラスインスタンスへのすべての参照が範囲外の場合、クラスインスタンスに割り当てられたメモリは、共通言語ランタイム(ガベージコレクション)によって自動的に再利用されます。
構造インスタンスの値の同等性
2つの構造インスタンスの比較は値の比較に基づいていますが、クラスインスタンスの比較はそれらの参照の比較です。
例の2つの本体の例の構造フィールドが同じ値であるかどうかを判別するにはValueType.Equals
、メソッドを使用します。すべての構造体は暗黙的にから継承System.ValueType
されるため、次の例に示すように、このメソッドはそのオブジェクトで直接呼び出すことができます。
public struct Person
{
public string Name;
public int Age;
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
static void Main()
{
Person p1 = new Person("技术译站", 100);
Person p2;
p2.Name = "技术译站";
p2.Age = 100;
if (p2.Equals(p1))
Console.WriteLine("p2 和 p1 有相同的值。");
Console.ReadKey();
}
// 输出: p2 和 p1 有相同的值。
System.ValueType
Equals
どのような構造を持っているフィールドを決定することができなければならないので、達成するためにリフレクションを使用します。独自の構造を作成する場合、rewriteEquals
メソッドは、求める効率的なアルゴリズムのタイプに固有の情報を提供する場合があります。
「値ベースの同等性」はrecord
、C#9.0の新しいレコード()タイプに似ています。C#9.0について知りたい場合は、次を確認できます。C#9.0へようこそ。
著者:Manju lata Yadav
翻訳者:Technical Zemin
出版社:Technical Verses
リンク:英語テキスト