Question List<T> working

Abdul Hayee

Member
Joined
Mar 31, 2020
Messages
24
Programming Experience
Beginner
I am learning c# and following an example from the docs.microsoft.com, link is below

Classes and objects - Introduction to C# tutorial

code is below
Main Program:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace classes
{
    class Program
    {
        static void Main(string[] args)
        {
            var Client1 = new BankAccounts("ABC", 1000);
            var Client2 = new BankAccounts("XYZ", 500);

            Console.WriteLine($"Account {Client1.Number} was created for {Client1.Owner} with {Client1.Balance} initial balance.");
            Console.WriteLine($"Account {Client2.Number} was created for {Client2.Owner} with {Client2.Balance} initial balance.");
            Console.WriteLine();

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

            Client2.MakeWithdrawal(500, DateTime.Now, "Fuel Charges");
            Console.WriteLine(Client2.Balance);
            Client2.MakeDeposit(100, DateTime.Now, "Bonus");
            Console.WriteLine(Client2.Balance);
            
            Console.WriteLine(Client1.GetAccountHistory());
            Console.WriteLine();
            Console.WriteLine(Client2.GetAccountHistory());

            Console.ReadLine();
        }
    }
}

BankAccount Class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace classes
{
    class BankAccounts
    {
        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 List<Transaction> allTransactions = new List<Transaction>();

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

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

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

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

    }
}

Transaction Class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

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)
        {
            Amount = amount;
            Date = date;
            Notes = note;
        }
    }
}

The example code is working fine but i have a query. In the example List<Transaction> allTransaction = new List<Transaction>() has been created.

I want to know that all the transactions made by different clients will be add to one "allTransaction" List or every client have its own "allTransaction" list? e.g Client1.allTransaction, Client2.allTransaction.....

for example i have made two clients in this example Client1 and Client2. Where are all of their transactions storing?

in the end of Program there is a GetAccountHistory() function which is showing history of Clients. How it is recognizing which transaction are of which Client.

Kindly guide me
Thanks
 
I think BankAccount class will be assigned to each Client. Right?
and what is inside BankAccount class will be replicated to each client
 
Each Client has it's own allTransactions. Look closely at the output of the code you presented above. Do you see the two different transactions getting mixed?

I recommend reviewing the concept of object instances and member variables.
 
Bad design if you ask me. Maybe for an example, it can be justified to dump methods into classes which should only be used for the contextual data that is held inside them. Classes are generally meant to have a single purpose usage.
Consider moving your methods to a business logic class or some static helper class instead.
 
Actually, except for the public list -- it should have been private at best, or only read-only at worse -- it's a great object oriented design especially from an academic point of view.

The issues just start cropping up when you start working in the industry and have to deal with the practicalities of having to persist data into a relational database management system (RDBMS) and/or having to deal with an ORM (Object-Relational Mapper), or serialize into JSON or XML. If you have an object oriented database management system, (OODBMS), it's still a great design. When you have to start playing with RDBMS's or having to serialize into JSON or XML, then playing with POCO's (Plain Old C# Objects) as DTO's (Data Transfer Objects) seems to be approach most people take. So unlike the academic object oriented approach where objects have both data and behavior, some industry programmers tend to take the approach of some objects have just data, while other objects have just behavior (aka business logic) and have the latter operate on the former.
 
I think BankAccount class will be assigned to each Client. Right?
and what is inside BankAccount class will be replicated to each client
That's the idea. It's pretty simple, really, but beginners tend to ignore the fact that the whole point of OOP is that programming objects are based on real-world objects and how they behave. Think the concept of a car. If I talk about cars to you, you know what I'm talking about, right? A metal box with an engine, four wheels, seats, etc, etc. That concept that we both understand is the class, i.e. the description of what the class is, has and does. That we understand what it is and can talk about it doesn't mean that either of us actually have one though. A manufacturer still needs to build the actual cars and then we need to buy them and take them home. If you and I both buy a car then they are both car objects that are based on the same template but have various differences and are distinct from each other. That's how OOP works. In your code, the BankAccount class is the template but each instance of that class you create - each object of that type - is different and distinct. A bank account is a bit more abstract than a car but, even in the real world, you wouldn't expect any overlap between them if you and I both went into the same branch and each opened a new bank account. Our money would not be mixed and our transaction histories would be completely separate.
 
Programming is all about abstraction. :) The art comes into when to apply the right level of abstraction vs. concreteness?

As an aside, I looked at the original link from the OP. The List allTransactions was marked as private in the Microsoft code.
 
Back
Top Bottom