やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

C#クイックスタート(クラス)

 最後のクイックスタート。

成果物

情報源

プロジェクト作成

dotnet new console -o classes
cd classes

コード

  • Program.cs
  • BankAccount.cs
  • Transaction.cs

Program.cs

using System;

namespace classes
{
    class Program
    {
        static void Main(string[] args)
        {
            var account = new BankAccount("<name>", 1000);
            Console.WriteLine($"Account {account.Number} was created for {account.Owner} with {account.Balance} initial balance.");

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

            // 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());
            }
            // 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());
            }
        }
    }
}

BankAccount.cs

using System;

namespace classes
{
    class BankAccount
    {
        private List<Transaction> allTransactions = new List<Transaction>();
        private static int accountNumberSeed = 1234567890;
        public string Number { get; }
        public string Owner { get; set; }
        public decimal Balance 
        {
            get
            {
                decimal balance = 0;
                foreach (var item in allTransactions)
                {
                    balance += item.Amount;
                }
                return balance;
            }
        }
        public BankAccount(string name, decimal initialBalance)
        {
            this.Number = accountNumberSeed.ToString();
            accountNumberSeed++;
            this.Owner = name;
            MakeDeposit(initialBalance, DateTime.Now, "Initial balance");
        }
        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);
        }
    }
}

Transaction.cs

using System;
using System.Collections.Generic;

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;
        }
    }
}

実行結果

$ dotnet run
Account 1234567890 was created for <name> with 1000 initial balance.
500
600
Exception caught creating account with negative balance
System.ArgumentOutOfRangeException: Amount of deposit must be positive (Parameter 'amount')
   at classes.BankAccount.MakeDeposit(Decimal amount, DateTime date, String note) in /tmp/work/classes/BankAccount.cs:line 35
   at classes.BankAccount..ctor(String name, Decimal initialBalance) in /tmp/work/classes/BankAccount.cs:line 29
   at classes.Program.Main(String[] args) in /tmp/work/classes/Program.cs:line 20
Exception caught trying to overdraw
System.InvalidOperationException: Not sufficient funds for this withdrawal
   at classes.BankAccount.MakeWithdrawal(Decimal amount, DateTime date, String note) in /tmp/work/classes/BankAccount.cs:line 49
   at classes.Program.Main(String[] args) in /tmp/work/classes/Program.cs:line 30

課題

 すべてのトランザクションをログに記録する。

コード

Program.cs

 以下を追記する。

Console.WriteLine(account.GetAccountHistory());

BankAccount.cs

 以下を追記する。

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

    report.AppendLine("Date\tAmount\tNote");
    foreach (var item in allTransactions)
    {
        report.AppendLine($"{item.Date.ToShortDateString()}\t{item.Amount}\t{item.Notes}");
    }

    return report.ToString();
}

実行結果

$ dotnet run
...
2019/10/18   1000   Initial balance
2019/10/18   -500   Rent payment
2019/10/18   100    Friend paid me back

所感

今回

 コピペで終わった感。自分でクラス設計を考えないと勉強できた気がしない。クラス設計の前に、アクセス修飾子、インタフェース、抽象クラスなど基礎構文について知りたかった。でもそれはクイックスタートっぽくないか。仕方ないね。

クイックスタートについて

 ここまでMicrosoftのクイックスタートを辿ってきた。わかりやすくて良かったのだが、文言の不統一が気になった。

  • 「配列とコレクション」と言っておきながらコレクションだけになっている
  • 「クイックスタート」「チュートリアル」「レッスン」「入門」と言ったりしている

 同じ概念をさすなら文言は統一してほしい。何が何やらわからなくなる。細かいことだが初学者にとっては大事。理解できるかどうかに関わる。文脈から大体わかるけど。

次回

 以下のリンクがあった。

C#のバージョン

 C#の最新バージョンっていくつなんだろ? 私が知っていたのは4.0で、今は8.0らしい。その間にある差を埋めねば……。サクッとググったら以下のようなリンクが出てきた。

対象環境

$ uname -a
Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux