C#のメンバ変数とは?フィールド・プロパティとの違いから使い分けまで初心者向けに解説

はじめに

C#を学び始めると、「メンバ変数」「フィールド」「プロパティ」という言葉が出てきます。どれもクラスの中で値を扱うときに関係する用語ですが、初心者にとっては違いが分かりにくい部分です。

特に「C#のメンバ変数とは何か」「フィールドと同じ意味なのか」「プロパティとはどう使い分けるのか」で迷う人は多いです。

この記事では、C#のメンバ変数について、基本的な意味から書き方、フィールド・プロパティとの違い、実務での使い分けまで初心者向けに解説します。

1. C#のメンバ変数とは?まずは基本を理解しよう

1-1. メンバ変数とはクラスや構造体に属する変数のこと

メンバ変数とは、クラスや構造体の中に定義され、そのクラスのデータを保持するための変数のことです。

たとえば、人物を表す Person クラスを作る場合、名前や年齢といった情報をクラスの中に持たせることがあります。

C#
class Person
{
string name;
int age;
}

この nameage のように、クラスに属している変数がメンバ変数です。

クラスから作られたオブジェクトは、それぞれ自分専用のメンバ変数の値を持つことができます。

C#
Person person1 = new Person();
Person person2 = new Person();

このとき、person1person2 は別々の名前や年齢を持つことができます。

1-2. C#では「メンバ変数」より「フィールド」と呼ばれることが多い

C#では、一般的に「メンバ変数」という言葉よりも「フィールド」という言葉がよく使われます。

他の言語では「メンバ変数」と呼ばれることが多いですが、C#の文脈では次のように理解すると分かりやすいです。

C#
class Sample
{
private int count;
}

この count は、C#では通常「フィールド」と呼びます。

つまり、C#で「メンバ変数」と言われた場合、多くの場合は「フィールド」のことを指していると考えて問題ありません。

ただし、厳密にはC#では「フィールド」「プロパティ」「メソッド」など、クラスに含まれる要素全体を「メンバー」と呼びます。そのため、C#では「メンバ変数」という言い方は少し曖昧で、正確には「フィールド」と表現するのが自然です。

1-3. ローカル変数との違い

メンバ変数とよく比較されるのがローカル変数です。

ローカル変数は、メソッドの中で宣言される変数です。

C#
class Calculator
{
private int total; // メンバ変数、フィールド

public void Add(int value)
{
int result = total + value; // ローカル変数
total = result;
}
}

この例では、total はクラスの中に定義されているためメンバ変数です。一方、resultAdd メソッドの中で定義されているためローカル変数です。

主な違いは、使える範囲と寿命です。

メンバ変数は、クラスの中の複数のメソッドから利用できます。一方、ローカル変数は宣言されたメソッドやブロックの中でしか使えません。

C#
class Counter
{
private int count;

public void Increment()
{
count++;
}

public void Show()
{
Console.WriteLine(count);
}
}

この count はメンバ変数なので、Increment メソッドでも Show メソッドでも使えます。

1-4. メンバ変数が使われる代表的な場面

メンバ変数は、オブジェクトの状態を保持したいときに使います。

たとえば、次のような場面です。

C#
class Player
{
private string name;
private int hp;
private int level;
}

この例では、プレイヤーの名前、HP、レベルをメンバ変数として持っています。

メンバ変数が使われる代表的な場面には、次のようなものがあります。

オブジェクトごとの状態を保存したい場合、クラス内の複数のメソッドで同じ値を使いたい場合、外部から見せたくない内部データを保持したい場合、設定値や共有データを管理したい場合などです。

C#では、これらの値を直接フィールドとして公開するのではなく、privateフィールドとpublicプロパティを組み合わせて扱うことがよくあります。

2. C#におけるメンバ変数の書き方

2-1. 基本構文

C#でメンバ変数を書く基本構文は次のとおりです。

C#
アクセス修飾子  変数名;

たとえば、整数型のメンバ変数を定義する場合は次のように書きます。

C#
private int count;

文字列を保持するメンバ変数であれば、次のようになります。

C#
private string name;

クラスの中、かつメソッドの外に書く点が重要です。

C#
class Sample
{
private int number; // メンバ変数

public void Method()
{
int value = 10; // ローカル変数
}
}

number はクラスに属しているためメンバ変数です。value はメソッドの中にあるためローカル変数です。

2-2. インスタンスフィールドの例

通常のメンバ変数は、インスタンスフィールドと呼ばれます。

インスタンスフィールドは、オブジェクトごとに別々の値を持ちます。

C#
class Person
{
private string name;

public void SetName(string value)
{
name = value;
}

public void ShowName()
{
Console.WriteLine(name);
}
}

このクラスから複数のオブジェクトを作ると、それぞれが別々の name を持ちます。

C#
Person person1 = new Person();
Person person2 = new Person();

person1.SetName("田中");
person2.SetName("佐藤");

person1.ShowName(); // 田中
person2.ShowName(); // 佐藤

このように、インスタンスフィールドはオブジェクトごとの状態を表すために使います。

2-3. staticフィールドの例

static を付けたメンバ変数は、staticフィールドと呼ばれます。

staticフィールドは、オブジェクトごとではなくクラス全体で共有される値です。

C#
class Counter
{
private static int totalCount;

public Counter()
{
totalCount++;
}

public static void ShowTotalCount()
{
Console.WriteLine(totalCount);
}
}

この例では、Counter オブジェクトが作られるたびに totalCount が増えます。

C#
Counter c1 = new Counter();
Counter c2 = new Counter();
Counter c3 = new Counter();

Counter.ShowTotalCount(); // 3

totalCount は各インスタンスに個別に存在するのではなく、Counter クラス全体で1つだけ存在します。

そのため、staticフィールドは共通設定や作成数のカウントなどに使われます。ただし、どこからでも共有される値になりやすいため、扱いには注意が必要です。

2-4. 初期値を設定する方法

メンバ変数には、宣言と同時に初期値を設定できます。

C#
class Player
{
private int hp = 100;
private int level = 1;
private string name = "No Name";
}

また、コンストラクターで初期化することもできます。

C#
class Player
{
private string name;
private int hp;

public Player(string name)
{
this.name = name;
hp = 100;
}
}

コンストラクターを使うと、オブジェクトを作るときに必要な値を渡して初期化できます。

C#
Player player = new Player("勇者");

C#では、フィールドに明示的な初期値を設定しない場合でも、型ごとに既定値が入ります。

C#
int number;       // 0
bool flag; // false
string text; // null

ただし、参照型のフィールドは null になる可能性があるため、初期化忘れには注意が必要です。

2-5. const・readonlyを使った定数や読み取り専用フィールド

C#では、値を変更させたくない場合に constreadonly を使います。

const はコンパイル時に値が決まる定数です。

C#
class MathSettings
{
public const double Pi = 3.14159;
}

const は、数値や文字列など、コンパイル時に確定できる値に使います。

C#
Console.WriteLine(MathSettings.Pi);

一方、readonly は、宣言時またはコンストラクター内でのみ値を設定できるフィールドです。

C#
class User
{
private readonly DateTime createdAt;

public User()
{
createdAt = DateTime.Now;
}
}

readonly は、オブジェクト作成後に変更したくない値を保持する場合に便利です。

const は完全な定数、readonly は初期化後に変更しないフィールド、と考えると分かりやすいです。

3. フィールド・プロパティ・メンバ変数の違い

3-1. フィールドとは

フィールドとは、クラスや構造体に直接定義される変数のことです。

C#
class Product
{
private int price;
}

この price がフィールドです。

フィールドは、クラス内部でデータを保持するために使われます。C#で「メンバ変数」と言われた場合、多くはこのフィールドのことを意味します。

フィールドには、インスタンスフィールドとstaticフィールドがあります。

C#
class Sample
{
private int instanceValue;
private static int sharedValue;
}

instanceValue はオブジェクトごとに持つ値、sharedValue はクラス全体で共有する値です。

3-2. プロパティとは

プロパティは、外部から値を取得したり設定したりするための仕組みです。

C#
class Person
{
public string Name { get; set; }
}

この Name がプロパティです。

プロパティは見た目は変数のように使えます。

C#
Person person = new Person();
person.Name = "田中";
Console.WriteLine(person.Name);

しかし、内部的には getset というアクセサーを通して値を取得・設定しています。

C#
class Person
{
private string name;

public string Name
{
get { return name; }
set { name = value; }
}
}

このように、プロパティを使うと、外部に公開する値の取得や変更をコントロールできます。

3-3. メンバ変数とフィールドの関係

C#では、メンバ変数という言葉は厳密な正式名称として使われるよりも、フィールドを説明するための一般的な言い方として使われることが多いです。

つまり、次のように考えると理解しやすいです。

C#
class Sample
{
private int count;
}

この count は、C#では「フィールド」と呼ぶのが正確です。ただし、他の言語や初心者向けの説明では「メンバ変数」と呼ばれることもあります。

一方、プロパティは変数ではありません。

C#
public int Count { get; set; }

これは値を持つように見えますが、C#の分類ではプロパティです。

そのため、C#では「メンバ変数=フィールド」と理解し、「プロパティとは別物」と押さえておくと混乱しにくくなります。

3-4. フィールドとプロパティの違いをコードで比較

フィールドとプロパティの違いをコードで見てみましょう。

まず、フィールドを直接publicにした例です。

C#
class Person
{
public int Age;
}

この場合、外部から自由に値を変更できます。

C#
Person person = new Person();
person.Age = -10;

年齢に -10 が入ってしまっても、クラス側で防ぐことができません。

次に、プロパティを使った例です。

C#
class Person
{
private int age;

public int Age
{
get
{
return age;
}
set
{
if (value < 0)
{
throw new ArgumentException("年齢に負の値は設定できません。");
}

age = value;
}
}
}

このようにプロパティを使うと、値を設定するときにチェック処理を入れられます。

また、自動実装プロパティを使うと、次のように短く書けます。

C#
class Person
{
public string Name { get; set; }
}

単純に値を公開したいだけなら、自動実装プロパティがよく使われます。

3-5. 初心者が混同しやすいポイント

初心者が混同しやすいのは、フィールドとプロパティが見た目として似ている点です。

C#
public string name;
public string Name { get; set; }

上はフィールド、下はプロパティです。

使う側から見ると、どちらも似たように使えます。

C#
person.name = "田中";
person.Name = "田中";

しかし、設計上は大きな違いがあります。

フィールドはデータそのものです。プロパティはデータにアクセスするための窓口です。

C#では、外部に値を公開する場合、publicフィールドではなくpublicプロパティを使うのが一般的です。

4. アクセス修飾子とメンバ変数の公開範囲

4-1. public

public は、どこからでもアクセスできることを表します。

C#
class Player
{
public int Hp;
}

この場合、クラスの外から直接アクセスできます。

C#
Player player = new Player();
player.Hp = 100;

ただし、メンバ変数を public にすると、外部から自由に値を変更できてしまいます。

C#
player.Hp = -999;

このような不正な値も入れられるため、publicフィールドは安易に使わない方がよいです。

4-2. private

private は、そのクラスの中からだけアクセスできることを表します。

C#
class Player
{
private int hp;

public void Damage(int amount)
{
hp -= amount;
}
}

この hp は、Player クラスの外から直接アクセスできません。

C#
Player player = new Player();
// player.hp = 100; // エラー

privateフィールドにすることで、値の変更方法をクラス内部で管理できます。

C#では、メンバ変数は基本的に private にすることが多いです。

4-3. protected

protected は、そのクラス自身と、継承した子クラスからアクセスできることを表します。

C#
class Character
{
protected int hp;
}

class Player : Character
{
public void Heal()
{
hp += 10;
}
}

この例では、Player クラスは Character クラスを継承しているため、protected フィールドである hp にアクセスできます。

ただし、外部からは直接アクセスできません。

C#
Player player = new Player();
// player.hp = 100; // エラー

protected は継承関係の中で使いたい値に利用します。

4-4. internal

internal は、同じアセンブリ内からアクセスできることを表します。

C#
internal class AppSettings
{
internal static string AppName = "SampleApp";
}

同じプロジェクト内で使うクラスやフィールドに対して利用されることがあります。

ただし、初心者が最初に意識すべきアクセス修飾子は、まず publicprivate です。internal は、プロジェクトやライブラリの設計に慣れてから理解していけば問題ありません。

4-5. メンバ変数は基本的にprivateにする理由

C#では、メンバ変数は基本的に private にするのが一般的です。

理由は、クラスの外から自由に変更されると、オブジェクトの状態を正しく保てなくなるからです。

たとえば、HPを表すフィールドがpublicだとします。

C#
class Player
{
public int Hp;
}

この場合、外部から不正な値を簡単に設定できます。

C#
Player player = new Player();
player.Hp = -100;

しかし、privateフィールドにしてメソッドやプロパティ経由で変更すれば、不正な値を防ぎやすくなります。

C#
class Player
{
private int hp;

public int Hp
{
get { return hp; }
private set
{
if (value < 0)
{
hp = 0;
}
else
{
hp = value;
}
}
}

public void Damage(int amount)
{
Hp -= amount;
}
}

このように、メンバ変数をprivateにすることで、データの安全性や保守性を高められます。

5. メンバ変数とプロパティの使い分け

5-1. 外部から直接変更させたくない場合はprivateフィールドを使う

外部から直接変更させたくない値は、privateフィールドとして定義します。

C#
class BankAccount
{
private decimal balance;
}

口座残高のような重要な値は、外部から直接書き換えられると危険です。

C#
// account.balance = 1000000; // privateなので外部からは変更できない

このような値は、専用のメソッドを通して変更するようにします。

C#
class BankAccount
{
private decimal balance;

public void Deposit(decimal amount)
{
if (amount <= 0)
{
throw new ArgumentException("入金額は0より大きい必要があります。");
}

balance += amount;
}
}

privateフィールドを使うことで、値の変更ルールをクラス内に閉じ込められます。

5-2. 外部に値を公開・設定させたい場合はプロパティを使う

外部から値を読み取ったり設定したりしたい場合は、プロパティを使います。

C#
class Person
{
public string Name { get; set; }
}

プロパティを使うと、外部からは次のように自然にアクセスできます。

C#
Person person = new Person();
person.Name = "田中";
Console.WriteLine(person.Name);

単純に値を保持して外部に公開したいだけなら、自動実装プロパティが便利です。

C#
public int Age { get; set; }

一方、外部から読み取りだけ許可したい場合は、set をprivateにできます。

C#
class User
{
public int Id { get; private set; }

public User(int id)
{
Id = id;
}
}

この場合、Id は外部から読み取れますが、外部から変更することはできません。

5-3. 入力チェックや加工が必要な場合はプロパティを使う

値を設定するときにチェックや加工が必要な場合は、プロパティを使います。

C#
class Person
{
private string name;

public string Name
{
get { return name; }
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("名前は空にできません。");
}

name = value.Trim();
}
}
}

この例では、空文字や空白だけの名前を防ぎ、余分な空白を取り除いています。

プロパティを使うことで、クラスの外からは簡単に値を設定でき、内部では必要なチェックを行えます。

C#
Person person = new Person();
person.Name = " 田中 ";

Console.WriteLine(person.Name); // 田中

このように、プロパティはデータの入口として使うと便利です。

5-4. 自動実装プロパティを使うべきケース

自動実装プロパティは、特別な処理が不要な場合に使います。

C#
class Product
{
public string Name { get; set; }
public int Price { get; set; }
}

このように書くと、C#が内部的にフィールドを用意してくれます。自分でprivateフィールドを書く必要はありません。

読み取り専用にしたい場合は、次のように書けます。

C#
class Product
{
public string Name { get; }
public int Price { get; }

public Product(string name, int price)
{
Name = name;
Price = price;
}
}

また、外部からは読み取れるが、変更はクラス内だけにしたい場合は次のように書きます。

C#
class Product
{
public string Name { get; private set; }
}

単純なデータ公開であれば、自動実装プロパティを使うのが実務でも一般的です。

5-5. 実務でよく使われる書き方

実務では、次のような書き方がよく使われます。

C#
class User
{
private readonly int id;

public int Id
{
get { return id; }
}

public string Name { get; set; }

public User(int id, string name)
{
this.id = id;
Name = name;
}
}

ただし、最近のC#では、単純な読み取り専用の値であれば自動実装プロパティで書くことも多いです。

C#
class User
{
public int Id { get; }
public string Name { get; set; }

public User(int id, string name)
{
Id = id;
Name = name;
}
}

入力チェックが必要な場合は、privateフィールドとプロパティを組み合わせます。

C#
class User
{
private string name;

public string Name
{
get { return name; }
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("名前は必須です。");
}

name = value;
}
}
}

実務では、「内部で使うだけならprivateフィールド」「外部に公開するならプロパティ」「チェックが必要ならプロパティに処理を書く」と覚えておくとよいでしょう。

6. C#のメンバ変数でよくある命名規則

6-1. privateフィールドにアンダースコアを付ける書き方

C#では、privateフィールドの名前にアンダースコアを付ける書き方がよく使われます。

C#
class Person
{
private string _name;
private int _age;
}

このようにすることで、privateフィールドであることが分かりやすくなります。

プロパティと組み合わせると、次のようになります。

C#
class Person
{
private string _name;

public string Name
{
get { return _name; }
set { _name = value; }
}
}

_name が内部で使うフィールド、Name が外部に公開するプロパティです。

6-2. camelCaseとPascalCaseの違い

C#の命名では、camelCaseとPascalCaseの違いも重要です。

camelCaseは、最初の単語を小文字で始める書き方です。

C#
private int userCount;
private string userName;

PascalCaseは、各単語の先頭を大文字にする書き方です。

C#
public int UserCount { get; set; }
public string UserName { get; set; }

一般的には、privateフィールドにはcamelCaseまたはアンダースコア付きcamelCase、publicプロパティにはPascalCaseを使うことが多いです。

C#
class User
{
private string _userName;

public string UserName
{
get { return _userName; }
set { _userName = value; }
}
}

このように名前の付け方を分けることで、フィールドとプロパティを見分けやすくなります。

6-3. プロパティ名との区別

privateフィールドとpublicプロパティを組み合わせる場合、名前が似ることがあります。

C#
private string name;

public string Name
{
get { return name; }
set { name = value; }
}

この例では、name がフィールドで、Name がプロパティです。

ただし、大文字小文字だけの違いだと見間違いやすい場合もあります。そのため、privateフィールドにアンダースコアを付ける書き方もよく使われます。

C#
private string _name;

public string Name
{
get { return _name; }
set { _name = value; }
}

どちらの書き方でも間違いではありませんが、プロジェクト内で統一することが大切です。

6-4. チームやプロジェクトのコーディング規約に合わせる重要性

命名規則は、チームやプロジェクトによって異なることがあります。

あるプロジェクトでは次のように書くかもしれません。

C#
private string _name;

別のプロジェクトでは、次のように書くかもしれません。

C#
private string name;

どちらが絶対に正しいというより、チーム全体で統一されていることが重要です。

同じプロジェクト内で書き方がバラバラだと、コードが読みにくくなります。

C#
private string _userName;
private int age;
private bool isActive;

このように混在していると、意図が分かりにくくなります。

実務では、自分の好みだけで書くのではなく、既存のコードやチームのコーディング規約に合わせるようにしましょう。

7. メンバ変数を使うときの注意点

7-1. publicフィールドを安易に使わない

C#では、publicフィールドを安易に使わないようにしましょう。

C#
class Person
{
public int Age;
}

このようにすると、外部から自由に値を変更できます。

C#
Person person = new Person();
person.Age = -20;

年齢にマイナスの値が入っても防げません。

プロパティを使えば、値のチェックができます。

C#
class Person
{
private int _age;

public int Age
{
get { return _age; }
set
{
if (value < 0)
{
throw new ArgumentException("年齢は0以上である必要があります。");
}

_age = value;
}
}
}

外部に公開する値は、基本的にpublicフィールドではなくpublicプロパティを使いましょう。

7-2. 不要なメンバ変数を増やさない

メンバ変数は便利ですが、必要以上に増やすとクラスの状態が複雑になります。

たとえば、一時的な計算結果をメンバ変数にしてしまうのは避けた方がよいです。

C#
class Calculator
{
private int result;

public int Add(int a, int b)
{
result = a + b;
return result;
}
}

この result は、メソッド内で一時的に使うだけならローカル変数で十分です。

C#
class Calculator
{
public int Add(int a, int b)
{
int result = a + b;
return result;
}
}

メンバ変数にするべきなのは、オブジェクトの状態として保持する必要がある値です。

一時的に使うだけの値は、ローカル変数にしましょう。

7-3. staticフィールドの扱いに注意する

staticフィールドは、クラス全体で共有される値です。

C#
class Settings
{
public static string CurrentUserName;
}

どこからでも変更できるstaticフィールドは、プログラムの状態を追いにくくする原因になります。

C#
Settings.CurrentUserName = "田中";
Settings.CurrentUserName = "佐藤";

どこで値が変わったのか分かりにくくなるため、バグの原因になることがあります。

staticフィールドを使う場合は、変更されない定数や、アプリ全体で本当に共有すべき値に限定するのがよいです。

C#
class AppConstants
{
public const int MaxRetryCount = 3;
}

変更可能なstaticフィールドを使う場合は、スレッドセーフや初期化タイミングにも注意が必要です。

7-4. nullや初期化忘れに注意する

参照型のメンバ変数は、初期化しないと null になることがあります。

C#
class User
{
private string name;

public void ShowName()
{
Console.WriteLine(name.Length);
}
}

この例では、namenull のままだと name.Length でエラーが発生します。

初期値を設定することで、nullによるエラーを防ぎやすくなります。

C#
class User
{
private string name = "";

public void ShowName()
{
Console.WriteLine(name.Length);
}
}

また、コンストラクターで必ず初期化する方法もあります。

C#
class User
{
private string name;

public User(string name)
{
this.name = name;
}
}

メンバ変数を使うときは、いつ、どこで、どの値に初期化されるのかを意識しましょう。

7-5. データの隠蔽を意識する

オブジェクト指向では、クラス内部のデータを外部から直接触らせない考え方が重要です。これをデータの隠蔽といいます。

たとえば、次のようにフィールドをpublicにすると、外部から自由に変更できてしまいます。

C#
class BankAccount
{
public decimal Balance;
}

この場合、残高を不正に書き換えることもできてしまいます。

C#
BankAccount account = new BankAccount();
account.Balance = -10000;

データを守るには、フィールドをprivateにし、必要な操作だけをメソッドやプロパティとして公開します。

C#
class BankAccount
{
private decimal _balance;

public decimal Balance
{
get { return _balance; }
}

public void Deposit(decimal amount)
{
if (amount <= 0)
{
throw new ArgumentException("入金額は0より大きい必要があります。");
}

_balance += amount;
}
}

このように、外部から直接データを変更させず、正しい操作だけを許可することが大切です。

8. メンバ変数の具体例で理解を深める

8-1. クラスに名前や年齢を保持する例

まずは、名前と年齢をメンバ変数として持つシンプルな例を見てみましょう。

C#
class Person
{
private string _name;
private int _age;

public Person(string name, int age)
{
_name = name;
_age = age;
}

public void Introduce()
{
Console.WriteLine($"私の名前は{_name}です。年齢は{_age}歳です。");
}
}

使い方は次のとおりです。

C#
Person person = new Person("田中", 25);
person.Introduce();

実行結果は次のようになります。

C#
私の名前は田中です。年齢は25歳です。

この例では、_name_age がメンバ変数です。Introduce メソッドからそれらの値を使っています。

8-2. privateフィールドとpublicプロパティを組み合わせる例

次に、privateフィールドとpublicプロパティを組み合わせる例です。

C#
class Person
{
private int _age;

public int Age
{
get { return _age; }
set
{
if (value < 0)
{
throw new ArgumentException("年齢は0以上である必要があります。");
}

_age = value;
}
}
}

このクラスでは、_age をprivateフィールドとして持ち、外部からは Age プロパティを通してアクセスします。

C#
Person person = new Person();
person.Age = 30;

Console.WriteLine(person.Age);

不正な値を設定しようとすると、例外が発生します。

C#
person.Age = -5; // エラー

このように、プロパティを使うと、値を安全に扱えます。

8-3. readonlyフィールドを使う例

readonly フィールドは、初期化後に変更したくない値に使います。

C#
class User
{
private readonly int _id;
private string _name;

public User(int id, string name)
{
_id = id;
_name = name;
}

public void Show()
{
Console.WriteLine($"ID: {_id}, Name: {_name}");
}
}

この例では、_id はコンストラクターで設定した後、変更できません。

C#
User user = new User(1, "田中");
user.Show();

IDのように、一度決めたら変更しない値には readonly が向いています。

一方、_name は通常のフィールドなので、クラス内で変更できます。

8-4. staticフィールドで共通の値を管理する例

staticフィールドを使うと、クラス全体で共有する値を管理できます。

C#
class User
{
private static int _count;

public string Name { get; }

public User(string name)
{
Name = name;
_count++;
}

public static int Count
{
get { return _count; }
}
}

この例では、User オブジェクトが作られるたびに _count が増えます。

C#
User user1 = new User("田中");
User user2 = new User("佐藤");

Console.WriteLine(User.Count); // 2

_count は各ユーザーが個別に持つ値ではなく、User クラス全体で共有される値です。

このように、staticフィールドはインスタンス全体に共通する情報を管理したいときに使います。

9. 初心者がつまずきやすいQ&A

9-1. メンバ変数とフィールドは同じ意味ですか?

C#では、メンバ変数と言われた場合、多くはフィールドのことを指します。

C#
class Sample
{
private int count;
}

この count はフィールドです。初心者向けの説明では、これをメンバ変数と呼ぶことがあります。

ただし、C#では正確には「フィールド」と呼ぶのが一般的です。

また、C#の「メンバー」には、フィールドだけでなく、プロパティ、メソッド、コンストラクターなども含まれます。そのため、「メンバ変数」という言葉は少し曖昧です。

C#を学ぶときは、「メンバ変数という言葉が出てきたら、基本的にはフィールドのこと」と理解しておくとよいでしょう。

9-2. C#ではメンバ変数をpublicにしてもよいですか?

文法上は、メンバ変数をpublicにできます。

C#
class Sample
{
public int Count;
}

しかし、実務ではpublicフィールドはあまり推奨されません。

理由は、外部から自由に値を変更できてしまうためです。

C#
Sample sample = new Sample();
sample.Count = -100;

このように、不正な値でも簡単に設定できてしまいます。

外部に値を公開したい場合は、publicフィールドではなくプロパティを使うのが一般的です。

C#
class Sample
{
public int Count { get; set; }
}

入力チェックが必要な場合は、privateフィールドとプロパティを組み合わせます。

C#
class Sample
{
private int _count;

public int Count
{
get { return _count; }
set
{
if (value < 0)
{
throw new ArgumentException("Countは0以上である必要があります。");
}

_count = value;
}
}
}

9-3. プロパティだけ使えばフィールドは不要ですか?

単純に値を保持して公開するだけなら、自動実装プロパティを使えばフィールドを自分で書かなくても済みます。

C#
class Person
{
public string Name { get; set; }
}

この場合、C#が内部的にフィールドを用意してくれます。

しかし、入力チェックや独自の処理が必要な場合は、privateフィールドを使うことがあります。

C#
class Person
{
private string _name;

public string Name
{
get { return _name; }
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("名前は必須です。");
}

_name = value;
}
}
}

また、クラス内部だけで使う値で、外部に公開する必要がない場合もprivateフィールドを使います。

C#
class Counter
{
private int _count;

public void Increment()
{
_count++;
}
}

つまり、プロパティだけで十分な場合もありますが、フィールドが不要になるわけではありません。

9-4. privateフィールドはどこからアクセスできますか?

privateフィールドは、そのフィールドを定義したクラスの中からだけアクセスできます。

C#
class Person
{
private string _name;

public void SetName(string name)
{
_name = name;
}

public void ShowName()
{
Console.WriteLine(_name);
}
}

この例では、SetName メソッドや ShowName メソッドから _name にアクセスできます。

しかし、クラスの外からはアクセスできません。

C#
Person person = new Person();
// person._name = "田中"; // エラー

外部から値を設定したい場合は、メソッドやプロパティを用意します。

C#
class Person
{
private string _name;

public string Name
{
get { return _name; }
set { _name = value; }
}
}

privateフィールドは、クラスの内部状態を守るために使われます。

9-5. staticメンバ変数はいつ使いますか?

staticメンバ変数は、クラス全体で共有したい値があるときに使います。

たとえば、作成されたオブジェクトの数を数える場合です。

C#
class InstanceCounter
{
private static int _count;

public InstanceCounter()
{
_count++;
}

public static int Count
{
get { return _count; }
}
}

使い方は次のとおりです。

C#
InstanceCounter a = new InstanceCounter();
InstanceCounter b = new InstanceCounter();

Console.WriteLine(InstanceCounter.Count); // 2

staticフィールドは、インスタンスごとではなくクラスに1つだけ存在します。

定数のような値にも使われます。

C#
class Constants
{
public const int MaxLength = 100;
}

ただし、変更可能なstaticフィールドは、どこから変更されたのか分かりにくくなることがあります。必要な場面に限定して使いましょう。

まとめ

C#のメンバ変数とは、クラスや構造体に属する変数のことです。ただし、C#では「メンバ変数」よりも「フィールド」と呼ぶのが一般的です。

メンバ変数は、クラス内でデータを保持するために使います。メソッド内で一時的に使うローカル変数とは異なり、クラス内の複数のメソッドから利用でき、オブジェクトの状態を表す役割を持ちます。

C#では、フィールドを直接publicにするのではなく、基本的にはprivateフィールドとして定義し、外部に公開する値はプロパティを使うのが一般的です。

C#
class Person
{
private string _name;

public string Name
{
get { return _name; }
set { _name = value; }
}
}

単純な値の公開であれば、自動実装プロパティもよく使われます。

C#
class Person
{
public string Name { get; set; }
}

メンバ変数を使うときは、アクセス修飾子、初期化、命名規則、staticフィールドの扱いに注意しましょう。

初心者のうちは、次のように覚えておくと分かりやすいです。

C#のメンバ変数は基本的にフィールドのこと、フィールドはクラス内部のデータ、プロパティは外部から値にアクセスするための窓口、メンバ変数は基本的にprivate、外部に公開するならプロパティを使う。

この考え方を押さえておくと、C#のクラス設計やオブジェクト指向の理解が深まり、より安全で読みやすいコードを書けるようになります。