C# & .NET Framework OOP — Building Blueprints
💡
Exercise 35

OOP Basics — Architect Certification Exam 20 XP Hard

Ctrl+Enter Run Ctrl+S Save

Architect, it's time for your OOP certification exam! These 15 questions cover the foundations of object-oriented programming in C# — from classes and constructors to memory, equality, and modern features. Many of these appear in real technical interviews. Take your time, think carefully, and prove you deserve the title of .NET Architect!

📋 Instructions
🧠 Quiz Time
0 / 15 answered
1
What is the fundamental difference between a class and a struct in C#?
A. Classes can have methods but structs cannot
B. Classes are reference types allocated on the heap; structs are value types typically allocated on the stack
C. Structs support inheritance but classes do not
D. There is no difference — they are interchangeable keywords
In C#, a class is a reference type (allocated on the managed heap, accessed via reference), while a struct is a value type (typically allocated on the stack or inline). Both can have methods, properties, and constructors, but structs cannot participate in inheritance (except implementing interfaces) and are best for small, lightweight data.
2
When you assign one object variable to another (e.g., `Building b2 = b1;`), what happens for reference types?
A. A deep copy of the object is created
B. Both variables point to the same object in memory — no copy is made
C. A shallow copy is automatically created using MemberwiseClone
D. The compiler throws an error — you must use Clone()
For reference types, assignment copies the reference (pointer), not the object. After `b2 = b1`, both b1 and b2 refer to the exact same object on the heap. Modifying the object through b2 will be visible through b1 and vice versa.
3
In what order are constructors executed when you chain them with `this()`? ```csharp public Building() : this("Default", 1) { Console.Write("A "); } public Building(string n, int f) { Console.Write("B "); } ``` What does `new Building()` print?
A. A B
B. B A
C. A only
D. B only
When constructor chaining with `this()`, the chained-to constructor executes FIRST, then the calling constructor's body runs. So `new Building()` chains to `Building(string, int)` which prints "B ", then returns to the default constructor's body which prints "A ". Output: "B A".
4
Which statement about static constructors in C# is TRUE?
A. A static constructor can accept parameters and be called explicitly
B. A static constructor runs once per class, automatically before the first instance is created or any static member is accessed
C. A static constructor can have a public or private access modifier
D. A class can have multiple static constructors via overloading
A static constructor runs exactly once per type, automatically triggered by the CLR before the first instance creation or first static member access. It cannot have parameters, cannot have access modifiers (it's implicitly private), cannot be called directly, and a class can have only one static constructor.
5
Which of the following is NOT a valid use of the `this` keyword in C#?
A. Referring to instance members to disambiguate from parameters with the same name
B. Chaining to another constructor in the same class with `: this(...)`
C. Passing the current instance as a parameter to another method
D. Using `this` inside a static method to access instance fields
`this` refers to the current instance of the class. Since static methods do not operate on an instance (they belong to the class itself), using `this` within a static method is a compile-time error. All other options are valid uses of `this`.
6
What is the difference between using a constructor and an object initializer? ```csharp var b1 = new Building("Tower", 10); // constructor var b2 = new Building { Name = "Tower", Floors = 10 }; // initializer ```
A. Object initializers bypass constructors entirely
B. Object initializers call the default constructor first, then set properties — constructors run custom logic directly
C. Constructors can only set fields, initializers can set properties
D. They are compiled to identical IL code with no behavioral difference
Object initializers are syntactic sugar: the compiler calls the default (parameterless) constructor first, then executes the property assignments afterward. The constructor approach runs your custom initialization logic directly. Key difference: object initializers require a accessible parameterless constructor and settable properties.
7
How does the .NET garbage collector determine that an object can be reclaimed?
A. It uses reference counting — when the count drops to zero, the object is freed
B. It traces from GC roots; objects not reachable from any root are eligible for collection
C. Objects are freed immediately when they go out of scope
D. The programmer must explicitly call GC.Free() on each object
.NET uses a tracing garbage collector, not reference counting. Starting from GC roots (static fields, local variables on the stack, CPU registers), the GC traces all reachable objects. Anything not reachable through this graph is eligible for collection. Objects are NOT freed when they go out of scope — collection happens at non-deterministic times.
8
What is a finalizer (destructor) in C#, and when should you use one? ```csharp class Building { ~Building() { /* cleanup */ } } ```
A. Finalizers are called immediately when an object goes out of scope and should always be implemented
B. Finalizers are called by the GC before reclaiming memory and should only be used for releasing unmanaged resources
C. Finalizers replace constructors and run when the object is created
D. The ~ClassName syntax is a C# compile error — finalizers don't exist in C#
A finalizer (~ClassName) is called by the garbage collector before reclaiming the object's memory. It is non-deterministic — you don't know when it will run. Finalizers add overhead (objects with finalizers survive an extra GC generation) and should ONLY be used as a safety net for releasing unmanaged resources (file handles, native memory). For deterministic cleanup, use IDisposable instead.
9
What is the purpose of `IDisposable` and the `using` statement?
A. `IDisposable` forces the garbage collector to run immediately
B. The `using` statement imports namespaces — it has nothing to do with IDisposable
C. `IDisposable.Dispose()` provides deterministic cleanup; `using` ensures Dispose is called even if an exception occurs
D. `IDisposable` is only used for database connections and has no other purpose
IDisposable provides a standard pattern for deterministic resource cleanup via the Dispose() method. The `using` statement (or `using` declaration in C# 8+) is syntactic sugar for a try/finally block that calls Dispose() automatically when the scope exits — even if an exception is thrown. This is essential for files, streams, database connections, and any unmanaged resource.
10
What is the difference between `readonly` and `const` fields in C#?
A. `const` is evaluated at compile-time and must be assigned at declaration; `readonly` is evaluated at runtime and can be assigned in the constructor
B. `readonly` fields can be changed any time; `const` cannot
C. They behave identically — the keywords are interchangeable
D. `const` can only be used with strings; `readonly` works with any type
`const` values are compile-time constants — they must be assigned at declaration, are implicitly static, and the value is baked into the IL at every usage site. `readonly` fields are runtime constants — they can be set at declaration or in a constructor, can differ per instance, and support any type including objects. If a referenced assembly changes a `const`, dependent assemblies must be recompiled.
11
What are partial classes in C# used for?
A. They allow a class definition to be split across multiple files, combined at compile time
B. They define a class that is only partially implemented and must be completed by a derived class
C. They create classes that are automatically garbage collected faster
D. They allow a class to inherit from multiple base classes
The `partial` keyword allows a single class definition to be split across two or more source files. At compile time, the compiler merges them into one class. This is commonly used by code generators (e.g., Windows Forms designer, EF scaffolding) so generated code and developer code stay in separate files without conflicts.
12
What is an anonymous type in C#, and what are its key characteristics? ```csharp var building = new { Name = "Tower", Floors = 30 }; ```
A. Anonymous types are mutable reference types that can be returned from methods
B. Anonymous types are compiler-generated immutable classes with read-only properties — their type name is generated and cannot be explicitly referenced
C. Anonymous types are value types stored on the stack
D. Anonymous types are identical to dynamic types
Anonymous types are compiler-generated classes with read-only (immutable) properties. The compiler generates a type name (like `<>f__AnonymousType0`) that you cannot reference in code — hence `var` is required. They override Equals() and GetHashCode() based on all properties. They are reference types (not value types) and are mainly used in LINQ queries.
13
What do record types (C# 9+) provide that regular classes do not by default? ```csharp public record Building(string Name, int Floors); ```
A. Records are value types like structs
B. Records provide value-based equality, immutability by default, built-in ToString, and a `with` expression for non-destructive mutation
C. Records cannot have methods or properties
D. Records are only usable in .NET 6+ and have no special features
Records (C# 9+) are reference types with compiler-generated value-based Equals/GetHashCode (comparing property values, not references), a readable ToString(), deconstruction, and the `with` expression (`b2 = b1 with { Floors = 50 }`) for creating modified copies. Positional records (as shown) have `init`-only properties, making them immutable by default. C# 10 added `record struct` for value-type records.
14
What does `MemberwiseClone()` produce, and what is the danger with reference-type fields? ```csharp class City { public string Name; public List<string> Buildings; } ```
A. A deep copy — all fields and nested objects are fully duplicated
B. A shallow copy — value-type fields are copied, but reference-type fields still point to the same objects
C. An empty object with all fields set to defaults
D. MemberwiseClone() does not exist in C#
MemberwiseClone() (inherited from System.Object) creates a shallow copy: value-type fields get independent copies, but reference-type fields copy only the reference. So both the original and clone share the same List<string> — modifying Buildings in one affects the other. For a true deep copy, you must manually clone all reference-type fields (or use serialization).
15
Given two `Building` objects with identical field values, what do `==` and `Equals()` return by default for classes? ```csharp var b1 = new Building { Name = "Tower" }; var b2 = new Building { Name = "Tower" }; Console.WriteLine(b1 == b2); Console.WriteLine(b1.Equals(b2)); ```
A. Both return True because the Name values match
B. `==` returns False (reference comparison); `Equals()` returns True (value comparison)
C. Both return False — for classes, both `==` and `Equals()` compare references by default, and b1 and b2 are different objects
D. Both throw a runtime exception
For classes (reference types), both `==` and `Equals()` perform reference equality by default — they check if two variables point to the same object in memory. Since b1 and b2 are separate objects created with separate `new` calls, both return False, even though their Name values are identical. To get value-based equality, you must override Equals() and GetHashCode() (or use a `record` type which does this automatically).
main.py
Hi! I'm Rex 👋
Output
Ready. Press ▶ Run or Ctrl+Enter.