Object-Oriented Programming (OOP) – Overview
- Object-oriented programming is a software development paradigm in which data is packaged with the operations that execute on it.
- In traditional programming, procedures and data were separate; in OOP they are combined into an object with fields (data) and methods (operations).
- The combined package is called an object; the data are fields and the operations are methods.
- OOP has been an industry-standard paradigm for decades due to its ability to produce solutions that scale more effectively than traditional approaches.
The Four Principles of OOP
- Abstraction – hide intricate and volatile details inside an object and expose a simplified external interface.
- Encapsulation – internal workings of an object are protected; use the object only through its external interface.
- Inheritance – create new objects that extend existing objects, reusing and augmenting existing behavior while preserving the same usage.
- Polymorphism – objects can behave in unique, individual ways when the same operations are performed on them.
Defining a Class
- A class is a fundamental concept in OOP for creating custom object types.
- C# is a class-based language; all code you write and all fields you create are part of a class (or struct).
- Classes are used for a variety of purposes and support multiple programming paradigms.
- A class provides a template for object creation and specifies details that apply to every member of the class, while also identifying attributes that may vary among instances.
- Think of a class as a cookie cutter and objects as cookies.
- A class groups related data and/or methods and encapsulates data with the operations that act on it.
- A class represents a custom type (though not all classes are custom types).
- Scenario: storing information about students.
- Instead of separate arrays for names, IDs, and GPAs (which risks being out of sync and complicates operations like sorting), use a class to group related data.
- Example attributes for a Student:
- Name as a string
- ID as an int
- GPA as a float
A Concrete Class Example: Student
- Class fields (as an example):
class Student {
public int ID;
public string Name;
public float GPA;
}
- Creating an array of students:
Student[] students = new Student[10];
- This example demonstrates storing related data together in a single type.
Instantiating a Class
- Objects are instances of classes.
- Instantiate objects with the new keyword:
Classname variablename = new Classname();
Student student = new Student();
- In the above example:
- Class: Student
- Object: student
- student is an instance of Student
Fields and Classes
- Fields: variables declared in classes that hold data relevant to that class (primitives, other objects, etc.).
- Access a field via the dot operator:
variablename.fieldname
. - Example:
student.ID = 12345678;
- Fields are sometimes called instance variables because they belong to a specific instance of a class.
- Unlike languages like JavaScript and Python, in C# an object's fields typically must be declared in the class definition (you cannot store arbitrary fields).
Methods
- Methods in C# are akin to functions/procedures in other languages.
- They may take parameters, execute a sequence of instructions, and optionally return a value.
- Method example:
double HarmonicMean(double a, double b) {
double mean = 2.0 * a * b / (a + b);
return mean;
}
- Method components: Return type, Method name, Parameters, Method signature, Body.
Void Methods
- A void method has a return type of
void
and does not return a value. - It is not required to have a return statement; execution returns when the method ends.
- A void method can still use a return statement to exit early, without returning a value:
public void PrintGreeting() {
Console.WriteLine("Hello World");
}
Invoking Methods on Objects
- Methods are invoked on objects that are instances of the class they belong to (except for static methods).
- Methods have access to the fields of the object on which they are invoked.
- Example:
class Coordinate {
int x, y;
public void PrintLocation() {
Console.WriteLine($"The coordinate is {x},{y}");
}
}
coordinate.PrintLocation();
Parameter Passing: in, ref, out
- Parameters can be prefixed with
in
, ref
, or out
to control how values are passed. in
– input-only; passes by reference but read-only inside method.out
– used to return values from a method; the method must assign a value to the parameter.ref
– passes by reference; the method can read and modify the original value.- Notes:
- The
ref
and out
keywords must be used on both the declaration and the call sites. in
parameters are read-only inside the method.
Parsing Strings to Numbers: int.Parse vs int.TryParse
int.Parse()
converts a string to an int but throws an exception if parsing fails.- Unhandled exceptions terminate the program; this is problematic when input can be unpredictable (e.g., user input).
int.TryParse()
uses an out parameter to return the parsed value and returns a boolean indicating success or failure.- Example:
int.TryParse("123", out int value);
Procedural Abstraction
- A fundamental abstraction concept in computer science.
- Identify common tasks and split them into procedures (functions/methods).
- Benefits:
- Reuse the procedure in multiple places.
- Reduces code size and bugs.
- Centralises changes when requirements change.
- Well-designed procedures are self-documenting.
Constructors
- Constructors are special methods used to initialize an object when it is created.
- Constructors have no return type.
- If no constructor is provided, a parameterless constructor is generated automatically.
- If you provide a constructor, an object cannot be created without calling it.
- Example with a parameterized constructor:
public Student(int id, string name, float gpa) {
ID = id;
Name = name;
GPA = gpa;
return;
}
// With a constructor: you must supply parameters
Student student = new Student(12345678, "Alice", 7.0f);
Creating Well-Designed Procedures
- Choose a good name: concise, descriptive, and self-documenting.
- Prefer an
Is
prefix for predicates that return a bool and do not mutate state (e.g. IsBlank()
, IsEmpty()
, IsActive()
). - Ensure the method does one thing; if naming is hard, the method may be doing too much.
- If the name is ambiguous, consider refactoring.
When Abstraction Isn’t Perfect
- Some details about a method’s internal workings cannot be captured fully in its name.
- These details should be documented thoroughly.
- Questions to ask regarding abstraction:
- What side effects does the method have?
- What will it do with the parameters?
- Does it rely on external state, and how?
- What can I do with the return value?
NULL VALUES and Nullable Types
null
means the reference points to no object; applicable to object references.- It is an error to call a method or access a field through a null reference.
- C# introduces nullable types to handle the potential for null values safely.
- Syntax: append
?
to a value type to make it nullable, e.g. int?
, string?
(reference types can also be nullable via ?
). - Compiler warnings help prevent null reference issues.
- Examples:
int[]? array;
Student? myStudent;
Null Operators
- Null coalescing operator:
??
- Null coalescing assignment:
??=
- Null conditional access:
?.
and ?[]
- Semantics:
L ?? R
returns L
if L
is not null; otherwise returns R
.L ??= R
assigns R
to L
if L
is null; otherwise does nothing.a?.b
accesses member b
only if a
is not null; otherwise returns null.a?[i]
accesses indexer only if a
is not null.
Examples Using Null Operators
string response = Console.ReadLine() ?? "";
Console.WriteLine("You entered a {0}-length string", response.Length);
string? response = Console.ReadLine();
response ??= "";
Console.WriteLine("You entered a {0}-length string", response.Length);
- Using null-conditional and length:
string? response = Console.ReadLine();
Console.WriteLine("You entered a {0}-length string", response?.Length);
- Accessing a character safely:
string? response = Console.ReadLine();
Console.WriteLine("The first character is {0}", response?[0]);
Nullable Parameters
- Methods can take nullable or non-nullable parameters.
- Nullable parameters effectively make the parameter optional; supplying
null
can carry a meaning. - The contract: a nullable parameter may be null; a non-nullable parameter is assumed not to be null.
- Compiler warnings may occur if non-nullable parameters could be null.
Overloading vs Overriding
- Method overloading allows multiple methods with the same name but different parameter lists within a class.
- Example, all methods named
Method
but with different argument types/counts:
public void Method(int a, int b)
public void Method(int a, float b)
public void Method(int a, int b, int c)
- The correct overload is chosen at compile time based on static types of the arguments.
- Important to distinguish from overriding (runtime polymorphism) which is not covered in this section.
Uses of Method Overloading
- Best used to provide different versions of a method that accept different argument shapes.
- Example: a drawing method with different overloads:
public void DrawRectangle(Coord topLeft, Coord topRight)
public void DrawRectangle(int x1, int y1, int x2, int y2)
- Overloads can return different types or have different access levels (though not recommended to rely on this).
- Overloading can become hard to maintain if overused.
- Prefer implementing overloads in terms of each other where possible (e.g., convert to a common form and delegate).
- If some arguments have default values, consider optional arguments instead of excessive overloading.
Optional Arguments (Default Values)
- Optional arguments allow omitting values in calls; defaults are supplied by the method signature.
- Example:
public decimal CalculatePrice(decimal gst = 0.10m)
- When not supplied, the optional argument takes its default value.
- Named arguments can be useful when there are multiple optional arguments:
decimal price = CalculatePrice(gst: 0.00m);
Visibility (Access Modifiers)
- Classes, methods, and fields can have visibility modifiers to control access.
- Main modifiers:
private
– internal to the class; private methods/fields can only be accessed by other members of the class.public
– accessible from anywhere.internal
– accessible within the same assembly; in many contexts equivalent to public for practical purposes in tutorials.
- Note: Visual Studio often shows
internal
by default in generated code. - For more details see official docs: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structures/access-modifiers
The this
Keyword
this
is used to refer to members of the current object.- Useful to disambiguate between local variables and fields when they have the same name (e.g., in constructors):
public class Example {
private float GPA;
public Example(float GPA) {
this.GPA = GPA;
}
}
- Without
this
, the local parameter could obscure the instance field.
- XML comments provide markup to describe classes, methods, or fields.
- Syntax uses three slashes:
///
followed by XML tags, e.g. <summary>
, <param>
, <returns>
. - They show up in IDE tooltips and help documents, improving API usability without digging into code:
/// <summary>
/// Returns the current location of this actor
/// </summary>
/// <param name="x">The actor's X coordinate</param>
/// <param name="y">The actor's Y coordinate</param>
public void GetLocation(out int x, out int y) { … }
Pre- and Post-Conditions
- A formal way to document method contracts.
- Pre-conditions describe what must be true before calling the method (caller’s responsibility):
/// <summary>
/// Sets the actor's location
/// Pre: x and y are both positive values
/// </summary>
public void SetLocation(int x, int y) { … }
- Post-conditions describe what must be true after the method executes (method guarantees):
/// Post: the actor's location is set to (x,y)
Properties
- Properties are a C# feature that behave like fields but are implemented via getters and setters.
- They act as a replacement for traditional getter/setter methods and can enforce invariants.
- Example of a class with properties and backing fields:
class Customer {
private string name;
private string addr;
private int id;
public string Name {
get { return name; }
set { name = value; }
}
public string Address {
get { return addr; }
set { addr = value; }
}
public int Id {
get { return id; }
set { id = value; }
}
}
Getters
- A property can have a getter that returns a value.
- Example:
public int Count {
get {
return customers.Count;
}
}
- A getter alone is read-only.
Setters
- A property may have a setter that validates and stores values:
public string Name {
set {
if (value == "" || value.Length > MAX_NAME_LENGTH) {
throw new ArgumentException("Invalid value for name");
}
name = value;
}
get {
return name;
}
}
Auto-Implemented Properties
- A shorthand that creates a private backing field automatically:
public string Address { get; set; }
- The compiler generates an anonymous backing field behind the scenes.
- You can still expose full property logic if needed by providing explicit getters/setters.
Auto-Implemented Properties vs Fields
- Auto-implemented properties are functionally identical to fields for storage but offer flexibility for future changes.
- Fields are harder to replace with properties without breaking the ABI (application binary interface).
- Auto-implemented properties allow changing to explicit properties later without breaking external code (though semantic changes may still affect callers).
Tips for Using Properties
- Use XML comments to describe properties (at the property level, not each getter/setter individually).
- Route all access to the backing field through the property to preserve restrictions.
- Ensure properties maintain the same semantics as fields (e.g., no unintended side effects in getters, setters that actually modify the value).
Static
- The keyword
static
has three meanings in C# depending on what it is applied to:- Static methods/properties
- Static fields
- Static classes
Static Methods and Properties
- Regular (non-static) methods require an instance of the class to be called.
- Example:
Employee.Pay()
is called on a specific employee to generate an invoice.
- Static methods do not operate on a specific instance; they are called on the class itself.
- Example:
Employee.PayAll(List<Employee> employees)
- Static methods are appropriate when the method does not need instance data.
Static Fields
- Static fields belong to the class, not to any instance.
- They can be accessed without an instance (e.g.,
ClassName.Field
). - They are dangerous and often discouraged for public use.
- Private static fields can be used in certain legitimate scenarios.
- One exception:
const
fields are implicitly static and allowed even if public.
Static Classes
- Static classes cannot be instantiated.
- They can contain only static methods and fields.
- Static classes are often used as utility containers for commonly used methods.
- They can have poor cohesion if a class collects unrelated methods merely for convenience.
Static - Conclusion (Best Practices)
- Use static methods/properties where appropriate.
- Avoid static fields unless there is a clear, legitimate need for a private static field.
- Never use public static fields.
- Use static classes where appropriate, but avoid grouping unrelated methods purely for convenience.
Acknowledgments and Closing
- The slides include an acknowledgment of traditional landowners (First Nations) and a general thanks.
- Acknowledgement of Traditional Owners: QUT acknowledges the Turrbal and Yugara as First Nations owners of the lands where QUT stands (cultural and teaching context).
- Harmonic mean example from methods:
- Harmonic mean of two numbers $a$ and $b$ is defined as
\text{mean} = \frac{2ab}{a+b}
Quick Reference: Terminology
- Class: a template for creating objects; defines fields and methods.
- Object/Instance: a concrete realization of a class.
- Field/Instance variable: data stored in an object.
- Method: a function that operates on an object and may read/modify its fields.
- Constructor: a special method used to initialize a new object; no return type.
- Getter/Setter: accessors for a property.
- Property: a member that provides controlled access to an internal field.
- Nullable type (suffix ?): allows a value type to be null.
- Null-coalescing operator:
??
. - Null-conditional access:
?.
and ?[]
. - In/Ref/Out: parameter passing modifiers with distinct semantics.
- Optional arguments: default parameter values; named arguments.
- Overloading: multiple methods with the same name but different parameter lists.
- Static vs instance members: class-level vs per-object.
End of Notes
- These notes reflect the contents of the CAB201 – Programming Principles transcript (object-oriented programming, C# concepts, and related practices) as presented in the slides.