Menu
Coddy logo textTech

Data Hiding Implementation

Part of the Object Oriented Programming section of Coddy's C# journey — lesson 33 of 70.

Data hiding goes beyond just using private fields. It's about designing your class so that internal implementation details are completely invisible to outside code, exposing only what's necessary through a clean public interface.

Consider a class that tracks a user's password. You don't want anyone accessing the raw password - not even to read it:

public class UserAccount
{
    private string passwordHash;
    
    public void SetPassword(string password)
    {
        passwordHash = HashPassword(password);
    }
    
    public bool VerifyPassword(string password)
    {
        return HashPassword(password) == passwordHash;
    }
    
    private string HashPassword(string password)
    {
        return password.GetHashCode().ToString();
    }
}

Notice there's no way to retrieve the password or even the hash. External code can only set a password or verify one - the internal storage mechanism is completely hidden. The HashPassword method is also private because it's an implementation detail that could change without affecting how the class is used.

This approach protects your class from misuse and gives you freedom to change internals later. If you decide to use a different hashing algorithm, no external code breaks because nothing depended on how the password was stored.

challenge icon

Challenge

Easy

Let's build a secure wallet system that demonstrates true data hiding. You'll create a digital wallet where the balance is completely protected from direct access - external code can only deposit, withdraw, and check if transactions are possible, but never see or manipulate the actual balance directly.

You'll organize your code across two files:

  • Wallet.cs: Create a Wallet class in the Finance namespace that keeps its balance completely hidden. The wallet should have:
    • A private field to store the balance (decimal)
    • A private method FormatBalance() that returns the balance formatted as a currency string like "$123.45" - this is an internal helper that shouldn't be exposed
    • A public method Deposit(decimal amount) that adds to the balance only if the amount is positive, returning true if successful, false otherwise
    • A public method Withdraw(decimal amount) that subtracts from the balance only if the amount is positive and doesn't exceed the current balance, returning true if successful, false otherwise
    • A public method CanAfford(decimal amount) that returns true if the balance is greater than or equal to the amount, false otherwise
    • A public method GetStatement() that uses the private FormatBalance() method internally and returns "Current balance: {formatted balance}"
    Notice there's no way to directly read or set the balance - you can only interact with it through controlled methods!
  • Program.cs: In your main file, create a Wallet and perform a series of transactions using input values. Show how the wallet protects its internal state while still providing useful functionality through its public interface.

You will receive three inputs:

  • Initial deposit amount (decimal)
  • Withdrawal amount to attempt (decimal)
  • Amount to check affordability for (decimal)

Print the output in this format:

Deposit {amount}: {True/False}
{GetStatement() result}
Withdraw {amount}: {True/False}
{GetStatement() result}
Can afford {amount}: {True/False}

For example, if the inputs are 100.50, 30.25, and 80.00, the output should be:

Deposit 100.50: True
Current balance: $100.50
Withdraw 30.25: True
Current balance: $70.25
Can afford 80.00: False

The key insight here is that external code never directly touches the balance field. Even the formatted balance string comes through a public method that internally uses a private helper. This is data hiding - the implementation details are completely invisible, and you're free to change how the balance is stored or formatted without breaking any code that uses your wallet!

Cheat sheet

Data hiding means designing classes so internal implementation details are completely invisible to outside code, exposing only what's necessary through a clean public interface.

Use private fields to store sensitive data and provide controlled access through public methods:

public class UserAccount
{
    private string passwordHash;
    
    public void SetPassword(string password)
    {
        passwordHash = HashPassword(password);
    }
    
    public bool VerifyPassword(string password)
    {
        return HashPassword(password) == passwordHash;
    }
    
    private string HashPassword(string password)
    {
        return password.GetHashCode().ToString();
    }
}

Key principles:

  • No direct access to internal data (no getters for sensitive fields)
  • Private helper methods for implementation details
  • Public methods provide controlled operations only
  • Internal storage mechanism is completely hidden

This protects the class from misuse and allows changing internal implementation without breaking external code.

Try it yourself

using System;
using Finance;

class Program
{
    public static void Main(string[] args)
    {
        // Read input values
        decimal depositAmount = Convert.ToDecimal(Console.ReadLine());
        decimal withdrawAmount = Convert.ToDecimal(Console.ReadLine());
        decimal checkAmount = Convert.ToDecimal(Console.ReadLine());

        // TODO: Create a Wallet instance
        
        // TODO: Perform deposit and print result in format: "Deposit {amount}: {True/False}"
        
        // TODO: Print the statement using GetStatement()
        
        // TODO: Perform withdrawal and print result in format: "Withdraw {amount}: {True/False}"
        
        // TODO: Print the statement using GetStatement()
        
        // TODO: Check affordability and print result in format: "Can afford {amount}: {True/False}"
    }
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming