1種類
1. クラスの概念
- クラスは現実世界の概念 (カプセル化、継承、ポリモーフィズム) を抽象化したものです。
- データメンバー: データを格納するクラス内の変数
- メンバー メソッド: データ メンバーを操作するクラス内の関数は、メンバー メソッドと呼ばれます。
- オブジェクト: クラスのインスタンス
- クラス定義
class X {…}
var instance = new X(…);
2. インスタンスフィールド
C# では、データ メンバーはフィールドと呼ばれます。特定のオブジェクトに関連するフィールドはインスタンス フィールドと呼ばれます。インスタンス フィールドは宣言時に初期化でき、初期化ステートメントはクラス コンストラクターの前に実行されます。次に例を示します。
class Employee
{
public string FirstName;
public string LastName;
public string Salary = "Not enough";
public Employee()
{
Salray= string.Empty;
}
}
インスタンス フィールドには、オブジェクトからのみアクセスできます。次に例を示します。
public static void Main()
{
Employee employee1 = new Employee();
Employee employee2;
employee2 = new Employee();
employee1.FirstName = "Inigo";
employee1.LastName = "Montoya";
employee1.Salary = "Too Little";
IncreaseSalary(employee1);
Console.WriteLine( "{0} {1}: {2}",employee1.FirstName, employee1.LastName,employee1.Salary);
}
static void IncreaseSalary(Employee employee)
{
employee.Salary = "Enough to survive on";
}
C# では、オブジェクトを通じてのみ呼び出すことができるメンバー メソッドをインスタンス メソッドと呼びます。
クラスのインスタンス メンバー内で、これを使用して、インスタンス メンバーを呼び出すためのオブジェクト参照を取得できます。次に例を示します。
class Employee
{
public string FirstName;
public string LastName;
public string Salary;
public string GetName()
{
return $"{ FirstName } { LastName }";
}
public void SetName(string newFirstName, string newLastName)
{
this.FirstName = newFirstName;
this.LastName = newLastName;
}
}
this キーワードを使用して、インスタンス メソッドを明示的に呼び出したり、メソッド呼び出しに渡したりすることもできます。次に例を示します。
class Employee
{
public string FirstName;
public string LastName;
public string Salary;
public string GetName() => $"{ FirstName } { LastName }";
public void SetName(string newFirstName, string newLastName)
{
this.FirstName = newFirstName;
this.LastName = newLastName;
Console.WriteLine( $"Name changed to '{ this.GetName() }'");
}
public void Save()
{
DataStorage.Store(this);
}
}
class DataStorage
{
// Save an employee object to a file named with the Employee name.
public static void Store(Employee employee) { ...}
}
3. アクセス修飾子
アクセス修飾子は、変更されたメンバーのカプセル化レベルを識別します。
- public: クラスまたはメンバーの修飾子; クラスまたはメンバーがクラスの外部からアクセスできることを示します
- private: member modifier; 変更されたメンバーが宣言されたクラス内でのみアクセス可能であることを示します
- protected: member 修飾子; 変更されたメンバーが宣言されたクラスまたは派生クラス内でのみアクセス可能であることを示します
- 内部: クラスまたはメンバーの修飾子。クラスまたはメンバーが同じアセンブリ内でのみアクセスできることを示します
- 保護された内部: クラスまたはメンバー修飾子。クラスまたはメンバーが現在のアセンブリまたは派生クラス内でのみアクセスできることを示します
class Employee
{
public string FirstName, LastName,Salary, Password;
private bool IsAuthenticated;
public bool Logon(string password)
{
if (Password == password)
IsAuthenticated = true;
return IsAuthenticated;
}
public bool GetIsAuthenticated() => IsAuthenticated;
// ...
}
4. メソッドパラメータ
デフォルトのアクセスレベルを入力します:
のメンバー | デフォルトのメンバーのアクセシビリティ | メンバーの許可された宣言されたアクセシビリティ |
列挙型 | 公共 | なし |
クラス | プライベート | 公共 保護された 内部 プライベート 保護された内部 |
インターフェース | 公共 | なし |
構造体 | プライベート | 公共 内部 プライベート |
5. 属性
プロパティは、フィールドとメンバー メソッドの特性を組み合わせたものです。オブジェクトのユーザーにとって、プロパティはフィールドのように見え、プロパティへのアクセスにはフィールドへのアクセスと同じ構文が使用されます。クラスの実装者にとって、プロパティは get アクセサーや set アクセサーで構成されるコードのブロックです。プロパティを読み取る場合は、get アクセサーのコード ブロックが実行され、プロパティに値を割り当てる場合は、set アクセサーのコード ブロックが実行されます。
set アクセサーのないプロパティは、読み取り専用プロパティと呼ばれます。get アクセサーのないプロパティは、書き込み専用プロパティと呼ばれます。上記のアクセサーの両方を持つプロパティは、読み取り/書き込みプロパティと呼ばれます。
フィールドとは異なり、プロパティは変数として分類されません。したがって、プロパティを ref パラメーターまたは out パラメーターとして渡すことはできません。
6. 属性を自動的に実装する
C# 3.0 以降では、プロパティ アクセサーに他のロジックが必要ない場合、自動的に実装されたプロパティによりプロパティ宣言がより簡潔になります。C# 6 以降では、自動実装されたプロパティをフィールドと同様に初期化できます。
public static void Main()
{
Employee employee1 = new Employee();
Employee employee2 = new Employee();
employee1.FirstName = "Inigo"; // Call the FirstName property's setter.
System.Console.WriteLine(employee1.FirstName); // Call the FirstName property's getter.
// Assign an auto-implemented property
employee2.Title = "Computer Nerd";
employee1.Manager = employee2;
// Print employee1's manager's title.
System.Console.WriteLine(employee1.Manager.Title);
}
class Employee
{
public string FirstName { get; set; }
private string LastName { get; set; }
public string Title { get; set; }
public Employee Manager { get; set; }
public string Salary { get; set; } = "Not Enough";
}
7. 属性のアクセス制限
デフォルトでは、get /set アクセサーは同じ可視性とアクセス レベルを持ちます。C# 2.0 以降では、プロパティの実装で get または set 部分にアクセス修飾子を指定することが許可され、その結果、プロパティに指定されたアクセス修飾子がオーバーライドされます。
プロパティでアクセス修飾子を使用するには、次の制限があります。
- アクセス修飾子は、インターフェイスまたは明示的に実装されたインターフェイス メンバーでは使用できません。
- アクセサー修飾子は、プロパティに set アクセサーと get アクセサーの両方が含まれている場合にのみ使用できます。この場合、修飾子はそのうちの 1 つに対してのみ許可されます。
- プロパティまたはインデクサーにオーバーライド修飾子がある場合、そのアクセサー修飾子は、オーバーロードされたアクセサーのアクセス修飾子 (存在する場合) と一致する必要があります。
- アクセサーのアクセシビリティ レベルは、プロパティ自体のアクセシビリティ レベルよりも厳しくする必要があります。
class Employee
{
public void Initialize(int id) => Id = id.ToString();
public string Id
{
get
{
return _Id;
}
private set
{
// Providing an access modifier is possible in C# 2.0 and higher only
_Id = value;
}
}
private string _Id;
}
2. コンストラクター
1. コンストラクター
1.1 コンストラクターはクラスと同じ名前を持つメソッドであり、戻り値はありません。次に例を示します。
class Employee
{
public Employee(string firstName, string lastName) // constructor
{
FirstName = firstName;
LastName = lastName;
}
public string FirstName { get; set; }
public string LastName { get; set; }
public string Title {get; set}
public string Salary { get; set; } = "Not Enough";
public string Name
{
get
{
return FirstName + " " + LastName;
}
set
{
string[] names;
names = value.Split(new char[] { ' ' });
if (names.Length == 2)
{
FirstName = names[0];
LastName = names[1];
}
else
{
throw new System.ArgumentException(string.Format($"Assigned value '{ value }' is invalid", nameof(value)));
}
}
}
}
1.2 コンストラクターを呼び出す
public static void Main()
{
Employee employee;
employee = new Employee("Inigo", "Montoya");
employee.Salary = "Too Little";
Console.WriteLine( "{0} {1}: {2}", employee.FirstName,
employee.LastName,employee.Salary);
}
1.3 デフォルトのコンストラクター
クラスでコンストラクターが明示的に定義されていない場合、C# コンパイラーはコンパイル時にパラメーターなしでコンストラクターを自動的に追加します。クラスがコンストラクターを明示的に定義すると、コンパイラーはデフォルトのコンストラクターを提供しません。
2. オブジェクト初期化子
Initializer は、オブジェクト内のすべてのアクセス可能なフィールドとプロパティを初期化するために使用されます。コンストラクターを呼び出すときに、次のように中括弧内にメンバー初期化リストを追加できます。
public static void Main()
{
Employee employee = new Employee("Inigo", "Montoya")
{
Title = "Computer Nerd",
Salary = "Not enough"
};
Console.WriteLine("{0} {1} ({2}): {3}", employee.FirstName, employee.LastName, employee.Title, employee.Salary);
}
3. コンストラクターチェーン
C# では、コロンの後に this キーワードを追加し、呼び出されるコンストラクターのパラメーター リストを追加することで、1 つのコンストラクターから同じクラスの別のコンストラクターを呼び出すことができます。次に例を示します。
class Employee
{
public Employee(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
public Employee(int id, string firstName, string lastName)
: this(firstName, lastName)
{
Id = id;
}
public Employee(int id)
{
Id = id;
// NOTE: Member constructors cannot be called explicitly inline
// this(id, firstName, lastName);
}
public int Id { get; private set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Salary { get; set; } = "Not Enough";
}
4.匿名型
匿名型はコンパイラによって動的に生成される型で、コンパイラが匿名型を検出すると、自動的に CIL クラスを生成します。このクラスには、匿名型宣言で指定された値とデータ型に対応するプロパティがあります。例えば:
public static void Main()
{
var patent1 =new
{
Title = "Bifocals",
YearOfPublication = "1784"
};
var patent2 =new
{
Title = "Phonograph",
YearOfPublication = "1877"
};
var patent3 =new
{
patent1.Title,
Year = patent1.YearOfPublication
};
System.Console.WriteLine("{0} ({1})",patent1.Title, patent1.YearOfPublication);
System.Console.WriteLine("{0} ({1})", patent2.Title, patent1.YearOfPublication);
Console.WriteLine();
Console.WriteLine(patent1);
Console.WriteLine(patent2);
Console.WriteLine();
Console.WriteLine(patent3);
}
3. 静的メンバー
1. 静的フィールド
クラスの複数のインスタンス間で共有されるフィールドは、static キーワードで識別されます。インスタンス フィールドと同様に、静的フィールドも宣言時に初期化できます。例えば:
class Employee
{
// ...
public static int Id; // default(int): 0
public static int NextId = 42;
// ...
}
インスタンス フィールドとは異なり、初期化されていない静的フィールドは、default(T) の結果であるデフォルト値を取得します。
2. 静的メソッド
静的フィールドと同様に、静的メソッドも static キーワードでマークされます。静的メソッドには、クラス名を介して直接アクセスできます。例えば:
public static void Main()
{
DirectoryInfo directory = new DirectoryInfo(".\\Source");
directory.MoveTo(".\\Root");
DirectoryInfoExtension.CopyTo(directory, ".\\Target", SearchOption.AllDirectories, "*");
}
public static class DirectoryInfoExtension
{
public static void CopyTo( DirectoryInfo sourceDirectory, string target, SearchOption option, string searchPattern)
{
if (target[target.Length - 1] != Path.DirectorySeparatorChar)
target += Path.DirectorySeparatorChar;
if (!Directory.Exists(target))
Directory.CreateDirectory(target);
for (int i = 0; i < searchPattern.Length; i++)
{
foreach (string file in Directory.GetFiles(sourceDirectory.FullName, searchPattern))
{
File.Copy(file, target + Path.GetFileName(file), true);
}
}
if (option == SearchOption.AllDirectories) //Copy subdirectories (recursively)
{
foreach (string element in Directory.GetDirectories(sourceDirectory.FullName))
Copy(element, target + Path.GetFileName(element),searchPattern);
}
}
private static void Copy(string element, string fileName, string searchPattern)
{
Console.WriteLine("Copying " + fileName);
}
}
3. 静的コンストラクター
静的コンストラクターは明示的に呼び出されませんが、実行時にクラスが最初にアクセスされたときに自動的に呼び出されます。クラスへの最初のアクセスは、通常のコンストラクターを使用するときに発生します。あるいは、クラスの静的メソッドまたはフィールドにアクセスするときに発生する場合もあります。静的コンストラクターはパラメーターを許可しません
class Employee
{
static Employee()
{
Random randomGenerator = new Random();
NextId = randomGenerator.Next(101, 999);
}
// ...
public static int NextId = 42;
// ...
}
4. 静的属性
プロパティは静的なものにすることもできます。例えば:
class Employee
{
// ...
public static int NextId
{
get
{
return _NextId;
}
private set
{
_NextId = value;
}
}
public static int _NextId = 42;
// ...
}
5. 静的クラス
静的クラスは C# でも定義できます。静的クラスには、インスタンス フィールドやメソッドは含まれません。したがって、静的クラスはインスタンス化できません。コンパイラは、静的クラスを自動的に抽象としてマークし、CIL コードにシールします。つまり、クラスを拡張不可として指定します。
public static class SimpleMath
{
public static int Max(params int[] numbers)
{
if (numbers.Length == 0) // Check that there is at least one item in numbers.
throw new ArgumentException( "numbers cannot be empty", nameof(numbers));
int result = numbers[0];
foreach (int number in numbers)
{
if (number > result)
result = number;
}
return result;
}
}
public class Program
{
public static void Main(string[] args)
{
int[] numbers = new int[args.Length];
for (int count = 0; count < args.Length; count++)
numbers[count] = args[count].Length;
Console.WriteLine( $@"Longest argument length = { SimpleMath.Max(numbers) }");
}
}
6. カプセル化されたデータ
6.1 定数フィールド
- const フィールドの値はコンパイル時に決定され、実行時には変更されません。定数フィールドは自動的に静的フィールドになります
- あるアセンブリが別のアセンブリの定数を参照する場合、その定数値は参照先アセンブリに直接コンパイルされます。
class ConvertUnits
{
public const float CentimersPerInch = 2.54F;
public const int CupsPerGallon = 16;
}
6.2 読み取り専用
readonly 修飾子はフィールドでのみ使用できます (ローカル変数では使用できません)。フィールド値はコンストラクターから、または宣言時にイニシャライザーを介してのみ変更できると記載されています。
class Employee
{
public Employee(int id)
{
_Id = id;
}
private readonly int _Id;
public int Id{
get { return _Id; }
}
// Error: A readonly field cannot be assigned to (excep in a constructor or a variable initializer)
// public void SetId(int id) =>_Id = id;
}
7. 部門カテゴリー
部分クラスは、完全なクラスに結合できるクラスの一部です。部分クラスは主に、クラスの定義を複数のファイルに分割するために使用されます。C# は、キーワード Partial を使用して部分クラスを宣言します。
// File: Program1.cs
partial class Program
{
}
// File: Program2.cs
partial class Program
{
}
8. 分割方法
部分メソッドは部分クラスに存在し、メソッドを 1 つのファイルで宣言し、別のファイルで実装することができます。例えば:
// File: Person.Designer.cs
public partial class Person
{
#region Extensibility Method Definitions
partial void OnLastNameChanging(string value);
partial void OnFirstNameChanging(string value);
#endregion
// ...
}
// File: Person.cs
partial class Person
{
partial void OnLastNameChanging(string value)
{
//...
}
partial void OnFirstNameChanging(string value)
{
//...
}
}