クラスおよびオブジェクトを使用したオブジェクト指向プログラミングについて確認しますExplore object oriented programming with classes and objects

このチュートリアルでは、開発用に使用できるマシンがあることを想定しています。This tutorial expects that you have a machine you can use for development. Windows、Linux、または macOS 上でローカルの開発環境を設定する手順については、.NET チュートリアル Hello World in 10 minutes (10 分で Hello World) に記載されています。The .NET tutorial Hello World in 10 minutes has instructions for setting up your local development environment on Windows, Linux, or macOS. 使用するコマンドの概要については、詳細な情報へのリンクが掲載されている、開発ツールに対する理解を深める方法に関するページをご覧ください。A quick overview of the commands you'll use is in the Become familiar with the development tools with links to more details.

アプリケーションを作成するCreate your application

ターミナル ウィンドウで、「 classes 」という名前のディレクトリを作成します。Using a terminal window, create a directory named classes . ここにアプリケーションを構築します。You'll build your application there. このディレクトリに移動し、コンソール ウィンドウで「dotnet new console」と入力します。Change to that directory and type dotnet new console in the console window. このコマンドにより、アプリケーションが作成されます。This command creates your application. Program.cs を開きます。Open Program.cs . 内容は次のようになります。It should look like this:

using System;

namespace classes
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

このチュートリアルでは、銀行口座を表す新しい型を作成します。In this tutorial, you're going to create new types that represent a bank account. 通常、開発者は各クラスを別々のテキスト ファイルで定義します。Typically developers define each class in a different text file. この方法なら、プログラムのサイズが大きくなっても管理が容易です。That makes it easier to manage as a program grows in size. classes ディレクトリに「 BankAccount.cs 」という名前の新しいファイルを作成します。Create a new file named BankAccount.cs in the classes directory.

このファイルには、" 銀行口座 " の定義が含まれます。This file will contain the definition of a * bank account _. オブジェクト指向プログラミングにより、" *クラス* " の形式で型が作成され、コードが整理されます。Object Oriented programming organizes code by creating types in the form of classes . これらのクラスには、特定のエンティティを表すコードが含まれています。These classes contain the code that represents a specific entity. BankAccount クラスは銀行口座を表します。The BankAccount class represents a bank account. コードでは、メソッドとプロパティを使用した特定の操作を実装します。The code implements specific operations through methods and properties. このチュートリアルでは、銀行口座は次の動作をサポートします。In this tutorial, the bank account supports this behavior:

  1. 銀行口座を一意に特定する 10 桁の数字をサポートしています。It has a 10-digit number that uniquely identifies the bank account.
  2. 口座の名前、または所有者の名前を格納する文字列をサポートしています。It has a string that stores the name or names of the owners.
  3. 残高を取得できます。The balance can be retrieved.
  4. 預金を許可します。It accepts deposits.
  5. 引き出しを許可します。It accepts withdrawals.
  6. 初期残高は正の値である必要があります。The initial balance must be positive.
  7. 引き出しによって残高が負の値になることはありません。Withdrawals cannot result in a negative balance.

銀行口座の型を定義するDefine the bank account type

動作を定義するクラスの基本を作成することから開始できます。You can start by creating the basics of a class that defines that behavior. File:New コマンドを使用して、新しいファイルを作成します。Create a new file using the _ File:New * command. BankAccount.cs という名前を付けます。Name it BankAccount.cs . BankAccount.cs ファイルに次のコードを追加します。Add the following code to your BankAccount.cs file:

using System;

namespace classes
{
    public class BankAccount
    {
        public string Number { get; }
        public string Owner { get; set; }
        public decimal Balance { get; }

        public void MakeDeposit(decimal amount, DateTime date, string note)
        {
        }

        public void MakeWithdrawal(decimal amount, DateTime date, string note)
        {
        }
    }
}

先に進む前に、構築したものを確認してみましょう。Before going on, let's take a look at what you've built. namespace 宣言は、コードを論理的に整理する方法を提供します。The namespace declaration provides a way to logically organize your code. このチュートリアルで取り扱うコードは比較的小さいため、1 つの名前空間にすべてのコードを配置します。This tutorial is relatively small, so you'll put all the code in one namespace.

public class BankAccount は、これから作成するクラスまたは型を定義します。public class BankAccount defines the class, or type, you are creating. クラス宣言のあとにある {} の内側はすべて、クラスの状態と動作を定義しています。Everything inside the { and } that follows the class declaration defines the state and behavior of the class. BankAccount クラスには、5 つの " メンバー " があります。There are five * members _ of the BankAccount class. 最初の 3 つは " *プロパティ* " です。The first three are properties . プロパティはデータ要素であり、検証やその他の規則を適用するコードを持つことができます。Properties are data elements and can have code that enforces validation or other rules. 最後の 2 つは " *メソッド* " です。The last two are methods . メソッドは 1 つの機能を実行するコード ブロックです。Methods are blocks of code that perform a single function. 各メンバーの名前を確認すると、開発者がそのクラスの作用を把握するための十分な情報が得られます。Reading the names of each of the members should provide enough information for you or another developer to understand what the class does.

新しいアカウントを開くOpen a new account

実装する最初の機能は、銀行口座を開く機能です。The first feature to implement is to open a bank account. 顧客が口座を開く場合、初期残高や口座の (1 名または複数名の) 所有者の情報を入力する必要があります。When a customer opens an account, they must supply an initial balance, and information about the owner or owners of that account.

BankAccount 型の新しいオブジェクトを作成することは、これらの値を割り当てる " *コンストラクター* " を定義することを意味します。Creating a new object of the BankAccount type means defining a constructor that assigns those values. " *コンストラクター* " はクラスと同じ名前のメンバーです。A constructor is a member that has the same name as the class. これは、そのクラス型のオブジェクトを初期化するために使用されます。It is used to initialize objects of that class type. BankAccount 型に次のコンストラクターを追加します。Add the following constructor to the BankAccount type. MakeDeposit クラス宣言の上に次のコードを配置します。Place the following code above the declaration of MakeDeposit:

public BankAccount(string name, decimal initialBalance)
{
    this.Owner = name;
    this.Balance = initialBalance;
}

new を使用してオブジェクトを作成すると、コンストラクターが呼び出されます。Constructors are called when you create an object using new. "Program.cs" の Console.WriteLine("Hello World!"); の行を次のコードに置き換えます (<name> は自分の名前に置き換えます)。Replace the line Console.WriteLine("Hello World!"); in _Program.cs* with the following code (replace <name> with your name):

var account = new BankAccount("<name>", 1000);
Console.WriteLine($"Account {account.Number} was created for {account.Owner} with {account.Balance} initial balance.");

これまでに構築したものを実行してみましょう。Let's run what you've built so far. Visual Studio を使用している場合は、 [実行] メニューから [デバッグなしで開始] を選択します。If you're using Visual Studio, Select Start without debugging from the Run menu. コマンド ラインを使用している場合は、プロジェクトを作成したディレクトリで dotnet run を入力します。If you're using a command line, type dotnet run in the directory where you've created your project.

口座番号が空であることに気付かれましたか?Did you notice that the account number is blank? 次にこの問題を解決します。It's time to fix that. 口座番号はオブジェクトが作成されるときに割り当てられる必要があります。The account number should be assigned when the object is constructed. しかし、それを作成する責任を呼び出し元に負わせるべきではありません。But it shouldn't be the responsibility of the caller to create it. BankAccount クラスのコードは、新しい口座番号の割り当て方を知っている必要があります。The BankAccount class code should know how to assign new account numbers. そのための簡単な方法は、10 桁の数字で始めることです。A simple way to do this is to start with a 10-digit number. そして、新しい口座番号が作成されるごとに値を 1 増加します。Increment it when each new account is created. 最後に、オブジェクトが作成されるときに現在の口座番号を格納します。Finally, store the current account number when an object is constructed.

BankAccountクラスにメンバーの宣言を追加します。Add a member declaration to the BankAccount class. BankAccount クラスの先頭の左中かっこ { の後に、次のコードを配置します。Place the following line of code after the opening brace { at the beginning of the BankAccount class:

private static int accountNumberSeed = 1234567890;

これがデータ メンバーです。This is a data member. これは private であり、BankAccount クラス内のコードのみがこれにアクセスできます。It's private, which means it can only be accessed by code inside the BankAccount class. この方法により、プライベートな実装 (口座番号の生成方法) から (口座番号を持つなどの) パブリックな責任を分離できます。It's a way of separating the public responsibilities (like having an account number) from the private implementation (how account numbers are generated). static でもあるため、すべての BankAccount オブジェクトによって共有されます。It is also static, which means it is shared by all of the BankAccount objects. 静的でない変数の値は BankAccount オブジェクトのインスタンスごとに一意です。The value of a non-static variable is unique to each instance of the BankAccount object. 次の 2 行をコンストラクターに追加して、口座番号を割り当てます。Add the following two lines to the constructor to assign the account number. それらは this.Balance = initialBalance という行の後に配置します。Place them after the line that says this.Balance = initialBalance:

this.Number = accountNumberSeed.ToString();
accountNumberSeed++;

dotnet run」と入力して結果を表示します。Type dotnet run to see the results.

預金と引き出しを作成するCreate deposits and withdrawals

銀行口座クラスは、預金と引き出しを許可して正しく動作するようにする必要があります。Your bank account class needs to accept deposits and withdrawals to work correctly. 口座のすべてのトランザクションを記録する履歴を作成して、預金と引き出しを実装しましょう。Let's implement deposits and withdrawals by creating a journal of every transaction for the account. これには、単純にトランザクションごとに残高を更新する方法に比べていくつかのメリットがあります。That has a few advantages over simply updating the balance on each transaction. 履歴は、すべてのトランザクションを監査して毎日の残高を管理するために使用できます。The history can be used to audit all transactions and manage daily balances. 必要に応じてすべてのトランザクションの履歴から残高を計算することにより、1 つのトランザクションの中で修正されたすべてのエラーが正しく残高に反映されて次の計算に使用されます。By computing the balance from the history of all transactions when needed, any errors in a single transaction that are fixed will be correctly reflected in the balance on the next computation.

トランザクションを表す新しい型を作成するところから始めましょう。Let's start by creating a new type to represent a transaction. これは一切の責任を持たない単純型です。This is a simple type that doesn't have any responsibilities. いくつかのプロパティが必要になります。It needs a few properties. Transaction.cs 」という名前の新しいファイルを作成します。Create a new file named Transaction.cs . これに次のコードを追加します。Add the following code to it:

using System;

namespace classes
{
    public class Transaction
    {
        public decimal Amount { get; }
        public DateTime Date { get; }
        public string Notes { get; }

        public Transaction(decimal amount, DateTime date, string note)
        {
            this.Amount = amount;
            this.Date = date;
            this.Notes = note;
        }
    }
}

BankAccount クラスに Transaction オブジェクトの List<T> を追加しましょう。Now, let's add a List<T> of Transaction objects to the BankAccount class. BankAccount.cs ファイルのコンストラクターの後に次の宣言を追加します。Add the following declaration after the constructor in your BankAccount.cs file:

private List<Transaction> allTransactions = new List<Transaction>();

List<T> クラスでは、別の名前空間をインポートする必要があります。The List<T> class requires you to import a different namespace. BankAccount.cs の最初に次を追加します。Add the following at the beginning of BankAccount.cs :

using System.Collections.Generic;

それでは、Balance を正しく計算しましょう。Now, let's correctly compute the Balance. 現在の残高は、すべての取引の値を合計することによって確認できます。The current balance can be found by summing the values of all transactions. 現在、このコードで取得できるのは口座の初期残高のみであるため、Balance プロパティを更新する必要があります。As the code is currently, you can only get the initial balance of the account, so you'll have to update the Balance property. BankAccount.cspublic decimal Balance { get; } の行を、次のコードに置き換えます。Replace the line public decimal Balance { get; } in BankAccount.cs with the following code:

public decimal Balance
{
    get
    {
        decimal balance = 0;
        foreach (var item in allTransactions)
        {
            balance += item.Amount;
        }

        return balance;
    }
}

この例は、" プロパティ " の重要な側面を示しています。This example shows an important aspect of * properties _. これで、別のプログラマーが値を要求したときに残高が計算されるようになりました。You're now computing the balance when another programmer asks for the value. この計算処理は、すべてのトランザクションを列挙して、その合計値を現在の残高として提供します。Your computation enumerates all transactions, and provides the sum as the current balance.

次に MakeDeposit メソッドと MakeWithdrawal メソッドを実装します。Next, implement the MakeDeposit and MakeWithdrawal methods. これらのメソッドは、初期残高が正の値でなければならず、引き出し後の残高が負の値になってはいけない、という最後の 2 つの規則を適用します。These methods will enforce the final two rules: that the initial balance must be positive, and that any withdrawal must not create a negative balance.

これにより、" *例外* " の概念が導入されます。This introduces the concept of exceptions . メソッドが作業を正常に完了できないことを示す標準的な方法は、例外をスローすることです。The standard way of indicating that a method cannot complete its work successfully is to throw an exception. 例外の型とそれに関連付けられたメッセージがエラーを説明します。The type of exception and the message associated with it describe the error. MakeDeposit メソッドは、預金額が負の値になる場合に例外をスローします。Here, the MakeDeposit method throws an exception if the amount of the deposit is negative. MakeWithdrawal メソッドは、引き出し額が負の値になる場合、または引き出しを適用した結果、残高が負の値になる場合に例外をスローします。The MakeWithdrawal method throws an exception if the withdrawal amount is negative, or if applying the withdrawal results in a negative balance. allTransactions リストの宣言の後に、次のコードを追加します。Add the following code after the declaration of the allTransactions list:

public void MakeDeposit(decimal amount, DateTime date, string note)
{
    if (amount <= 0)
    {
        throw new ArgumentOutOfRangeException(nameof(amount), "Amount of deposit must be positive");
    }
    var deposit = new Transaction(amount, date, note);
    allTransactions.Add(deposit);
}

public void MakeWithdrawal(decimal amount, DateTime date, string note)
{
    if (amount <= 0)
    {
        throw new ArgumentOutOfRangeException(nameof(amount), "Amount of withdrawal must be positive");
    }
    if (Balance - amount < 0)
    {
        throw new InvalidOperationException("Not sufficient funds for this withdrawal");
    }
    var withdrawal = new Transaction(-amount, date, note);
    allTransactions.Add(withdrawal);
}

throw ステートメントで例外が " スロー " されます。The throw statement _ throws * an exception. 現在のブロックの実行が終了し、コントロールによってコール スタックで最初に一致した catch ブロックに転送されます。Execution of the current block ends, and control transfers to the first matching catch block found in the call stack. あとで catch ブロックを追加してこのコードをテストします。You'll add a catch block to test this code a little later on.

残高を直接更新するのではなく、最初のトランザクションを追加するようにするため、コンストラクターを 1 か所変更する必要があります。The constructor should get one change so that it adds an initial transaction, rather than updating the balance directly. 既に MakeDeposit メソッドは記述したので、このメソッドをコンストラクターから呼び出します。Since you already wrote the MakeDeposit method, call it from your constructor. 完成したコンストラクターは次のようになります。The finished constructor should look like this:

public BankAccount(string name, decimal initialBalance)
{
    this.Number = accountNumberSeed.ToString();
    accountNumberSeed++;

    this.Owner = name;
    MakeDeposit(initialBalance, DateTime.Now, "Initial balance");
}

DateTime.Now は、現在の日付と時刻を返すプロパティです。DateTime.Now is a property that returns the current date and time. 新しい BankAccount を作成するコードの後で、Main メソッドにいくつかの預金と引き出しを追加することで、これをテストします。Test this by adding a few deposits and withdrawals in your Main method, following the code that creates a new BankAccount:

account.MakeWithdrawal(500, DateTime.Now, "Rent payment");
Console.WriteLine(account.Balance);
account.MakeDeposit(100, DateTime.Now, "Friend paid me back");
Console.WriteLine(account.Balance);

次に、残高が負の値になっている口座を作成してみることで、エラー条件のキャッチをテストします。Next, test that you are catching error conditions by trying to create an account with a negative balance. 追加したコードの後に、次のコードを追加します。Add the following code after the preceding code you just added:

// Test that the initial balances must be positive.
try
{
    var invalidAccount = new BankAccount("invalid", -55);
}
catch (ArgumentOutOfRangeException e)
{
    Console.WriteLine("Exception caught creating account with negative balance");
    Console.WriteLine(e.ToString());
}

trycatch のステートメントを使用して、例外をスローする可能性のあるコード ブロックをマークし、想定したエラーをキャッチします。You use the try and catch statements to mark a block of code that may throw exceptions and to catch those errors that you expect. 同じ方法で、残高が負の値になっている場合に例外をスローするコードをテストします。You can use the same technique to test the code that throws an exception for a negative balance. Main メソッドの末尾に、次のコードを追加します。Add the following code at the end of your Main method:

// Test for a negative balance.
try
{
    account.MakeWithdrawal(750, DateTime.Now, "Attempt to overdraw");
}
catch (InvalidOperationException e)
{
    Console.WriteLine("Exception caught trying to overdraw");
    Console.WriteLine(e.ToString());
}

ファイルを保存し、「dotnet run」と入力して試します。Save the file and type dotnet run to try it.

課題 - すべてのトランザクションをログに記録するChallenge - log all transactions

このチュートリアルを完了すると、トランザクション履歴の string を作成する GetAccountHistory メソッドを記述できるようになります。To finish this tutorial, you can write the GetAccountHistory method that creates a string for the transaction history. このメソッドを BankAccount 型に追加します。Add this method to the BankAccount type:

public string GetAccountHistory()
{
    var report = new System.Text.StringBuilder();

    decimal balance = 0;
    report.AppendLine("Date\t\tAmount\tBalance\tNote");
    foreach (var item in allTransactions)
    {
        balance += item.Amount;
        report.AppendLine($"{item.Date.ToShortDateString()}\t{item.Amount}\t{balance}\t{item.Notes}");
    }

    return report.ToString();
}

これは、StringBuilder クラスを使用して、各トランザクションを 1 行で表す文を含んだ文字列をフォーマットします。This uses the StringBuilder class to format a string that contains one line for each transaction. 文字列をフォーマットするコードについては、このチュートリアルで先述しました。You've seen the string formatting code earlier in these tutorials. 新しい文字の 1 つは \t です。One new character is \t. これはタブを挿入して出力をフォーマットします。That inserts a tab to format the output.

次の行を追加して、 Program.cs でテストします。Add this line to test it in Program.cs :

Console.WriteLine(account.GetAccountHistory());

プログラムを実行して結果を確認します。Run your program to see the results.

次の手順Next steps

うまくいかない場合は、このチュートリアルのソースを GitHub リポジトリで確認できます。If you got stuck, you can see the source for this tutorial in our GitHub repo.

オブジェクト指向プログラミングのチュートリアルに進むことができます。You can continue with the object oriented programming tutorial.

次の記事でこれらの概念の詳細を学習できます。You can learn more about these concepts in these articles: