Bird
Raised Fist0
C Sharp (C#)programming~30 mins

Indexer with custom types in C Sharp (C#) - Mini Project: Build & Apply

Choose your learning style10 modes available
Indexer with Custom Types in C#
📖 Scenario: You are creating a simple library system to manage books. Each book has a unique ID and a title. You want to access books easily using their ID.
🎯 Goal: Build a class Library that stores books and allows accessing them using an indexer with a custom type BookID.
📋 What You'll Learn
Create a struct called BookID with an integer field Id
Create a class called Book with a string property Title
Create a class called Library that stores books in a dictionary with BookID as key
Add an indexer in Library to get and set Book objects by BookID
Demonstrate adding and retrieving books using the indexer
💡 Why This Matters
🌍 Real World
Indexers with custom types are useful when you want to access complex data collections using meaningful keys, like IDs or codes.
💼 Career
Understanding indexers and custom types helps in building clean, readable code for managing data in software development jobs.
Progress0 / 4 steps
1
Create the BookID struct and Book class
Create a struct called BookID with a public integer field Id. Also create a class called Book with a public string property Title that has get and set accessors.
C Sharp (C#)
Hint

Think of BookID as a simple label for books. The Book class holds the book's title.

2
Create the Library class with a dictionary to store books
Create a class called Library. Inside it, create a private dictionary called books that uses BookID as key and Book as value. Initialize books in the constructor.
C Sharp (C#)
Hint

The dictionary will help you store and find books by their BookID.

3
Add an indexer to Library to get and set books by BookID
Inside the Library class, add a public indexer that takes a BookID parameter and returns a Book. The indexer should get the book from the books dictionary if it exists, or return null if not. It should also allow setting a book for a given BookID.
C Sharp (C#)
Hint

The indexer lets you write library[bookId] to get or set a book.

4
Add books and print their titles using the indexer
Create a Library object called library. Add two books with BookID values 1 and 2 and titles "C# Basics" and "Advanced C#" using the indexer. Then print the titles of these books using the indexer.
C Sharp (C#)
Hint

Use the indexer to add and then print book titles by their BookID.

Practice

(1/5)
1.

What is the main purpose of an indexer in a C# class?

Choose the best description.

easy
A. To create a constructor for initializing objects.
B. To define a method that returns the size of a collection.
C. To allow objects to be accessed using array-like bracket syntax with custom keys.
D. To overload the + operator for custom types.

Solution

  1. Step 1: Understand what an indexer does

    An indexer lets you use square brackets [] to access elements inside an object, similar to arrays.
  2. Step 2: Identify the correct description

    Only To allow objects to be accessed using array-like bracket syntax with custom keys. describes this behavior correctly by mentioning bracket syntax and custom keys.
  3. Final Answer:

    To allow objects to be accessed using array-like bracket syntax with custom keys. -> Option C
  4. Quick Check:

    Indexer = bracket access [OK]
Hint: Indexers let you use [] on objects like arrays [OK]
Common Mistakes:
  • Confusing indexers with constructors
  • Thinking indexers define collection size
  • Mixing indexers with operator overloading
2.

Which of the following is the correct syntax to declare an indexer in a C# class using a custom type Key as the index?

public class MyCollection {
    // Indexer declaration here
}
easy
A. public string this[Key key] { get; set; }
B. public string this(Key key) { get; set; }
C. public string this[Key] { get; set; }
D. public string this[Key key] => get; set;

Solution

  1. Step 1: Recall indexer syntax

    Indexers use the keyword this followed by square brackets with the parameter type and name inside.
  2. Step 2: Check each option

    public string this[Key key] { get; set; } correctly uses this[Key key] with get and set accessors. Others have syntax errors or wrong brackets.
  3. Final Answer:

    public string this[Key key] { get; set; } -> Option A
  4. Quick Check:

    Indexer syntax = this[Type name] { get; set; } [OK]
Hint: Indexer uses this[Type name] with get/set inside braces [OK]
Common Mistakes:
  • Using parentheses instead of brackets
  • Omitting parameter name in brackets
  • Using expression-bodied syntax incorrectly
3.

Given the following code, what will be the output?

public record Key(int Id);

public class Store {
    private Dictionary<Key, string> data = new();
    public string this[Key key] {
        get => data.TryGetValue(key, out var val) ? val : "Not found";
        set => data[key] = value;
    }
}

var store = new Store();
store[new Key(1)] = "Apple";
store[new Key(2)] = "Banana";
Console.WriteLine(store[new Key(1)]);
Console.WriteLine(store[new Key(3)]);
medium
A. Not found\nNot found
B. Apple\nBanana
C. Compilation error
D. Apple\nNot found

Solution

  1. Step 1: Understand how the indexer accesses data

    The indexer uses a Dictionary with Key as key type. It returns the value if found, else "Not found".
  2. Step 2: Check the keys used

    Keys with Id 1 and 2 are added. Accessing new Key(1) finds "Apple". Accessing new Key(3) is missing, so returns "Not found".
  3. Final Answer:

    Apple Not found -> Option D
  4. Quick Check:

    Key(1) found, Key(3) missing = Apple, Not found [OK]
Hint: Indexer uses dictionary lookup; missing keys return default [OK]
Common Mistakes:
  • Assuming new Key(1) is different from stored Key(1)
  • Expecting Banana for Key(3)
  • Ignoring TryGetValue fallback
4.

Identify the error in the following code snippet that implements an indexer with a custom type Key:

public class DataStore {
    private Dictionary<Key, int> dict = new();
    public int this[Key key] {
        get { return dict[key]; }
        set { dict.Add(key, value); }
    }
}
medium
A. Using dict.Add in set causes exception if key exists; should use dict[key] = value.
B. Indexer must return string, not int.
C. Key type cannot be used as indexer parameter.
D. Missing constructor for DataStore class.

Solution

  1. Step 1: Analyze the set accessor

    The set accessor uses dict.Add(key, value), which throws an exception if the key already exists.
  2. Step 2: Suggest correct usage

    To update or add, use dict[key] = value; which overwrites existing or adds new key.
  3. Final Answer:

    Using dict.Add in set causes exception if key exists; should use dict[key] = value. -> Option A
  4. Quick Check:

    dict.Add throws if key exists; use dict[key] = value [OK]
Hint: Use dict[key] = value to avoid exceptions on set [OK]
Common Mistakes:
  • Using Add instead of index assignment in set
  • Thinking Key cannot be indexer parameter
  • Confusing return types in indexer
5.

You want to create a class Matrix that uses a custom struct Position as the indexer key to store integer values. The Position struct has two int fields: Row and Col. Which approach correctly implements the indexer to allow getting and setting values by Position?

public struct Position {
    public int Row, Col;
    public Position(int r, int c) { Row = r; Col = c; }
}

public class Matrix {
    private Dictionary<Position, int> values = new();
    // Implement indexer here
}
hard
A. public int this[Position pos] { get => values[pos]; set => values[pos] = value; }
B. public int this[Position pos] { get => values.TryGetValue(pos, out var v) ? v : 0; set => values[pos] = value; }
C. public int this[Position pos] { get { return values[pos]; } set { values.Add(pos, value); } }
D. public int this[int row, int col] { get => values[new Position(row, col)]; set => values[new Position(row, col)] = value; }

Solution

  1. Step 1: Consider safe get behavior

    Using TryGetValue with fallback 0 avoids exceptions if the position key is missing.
  2. Step 2: Check set accessor correctness

    Using values[pos] = value; safely adds or updates the dictionary entry.
  3. Step 3: Evaluate other options

    public int this[int row, int col] { get => values[new Position(row, col)]; set => values[new Position(row, col)] = value; } uses two parameters, not matching the question's single Position key. public int this[Position pos] { get { return values[pos]; } set { values.Add(pos, value); } } uses Add in set, which throws if key exists. public int this[Position pos] { get => values[pos]; set => values[pos] = value; }'s get accessor throws if key missing.
  4. Final Answer:

    public int this[Position pos] { get => values.TryGetValue(pos, out var v) ? v : 0; set => values[pos] = value; } -> Option B
  5. Quick Check:

    Safe get with TryGetValue + index assignment set [OK]
Hint: Use TryGetValue in get to avoid exceptions on missing keys [OK]
Common Mistakes:
  • Using Add in set causing exceptions
  • Not handling missing keys in get
  • Using multiple parameters instead of custom type
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard