Skip to main content

.NET Objects

Introduction

Objects are the foundation of object-oriented programming in .NET. They are instances of classes that encapsulate data (properties, fields) and behavior (methods) into a single unit. Understanding objects is crucial for becoming proficient in .NET development, as nearly everything in .NET is an object.

In this guide, we'll explore what objects are in the .NET framework, how to create and manipulate them, and how they form the building blocks of your applications.

What Are Objects in .NET?

An object in .NET is an instance of a class, which is a blueprint that defines the data and behavior the object will have. Think of a class as a cookie cutter, and objects as the cookies you make with it—each cookie (object) has the same shape (structure) defined by the cutter (class), but can have different characteristics (property values).

Key Characteristics of Objects

  • State - Objects store data in fields and properties
  • Behavior - Objects expose functionality through methods
  • Identity - Each object has a unique identity in memory
  • Lifetime - Objects are created and eventually destroyed when no longer needed

Creating Objects in .NET

There are several ways to create objects in .NET:

Using the new Keyword

The most common way to create an object is using the new keyword:

csharp
// Create a new object of type Person
Person person1 = new Person();

// Create and initialize in one statement (C# 3.0+)
Person person2 = new Person { Name = "John", Age = 30 };

Using Object Initializers

C# 3.0 introduced object initializers, which allow you to set properties right after creating an object:

csharp
// Using object initializer syntax
var car = new Car
{
Make = "Toyota",
Model = "Corolla",
Year = 2023
};

Using Factory Methods

Sometimes classes provide static factory methods to create instances:

csharp
// Using a factory method
DateTime now = DateTime.Now;
List<string> list = Enumerable.Range(1, 10).Select(n => n.ToString()).ToList();

Working with Object Properties

Properties are special members that provide a flexible mechanism to read, write, or compute the value of a private field:

csharp
public class Person
{
// Auto-implemented property
public string Name { get; set; }

// Property with backing field
private int _age;
public int Age
{
get { return _age; }
set
{
if (value >= 0)
_age = value;
else
throw new ArgumentException("Age cannot be negative");
}
}

// Read-only property
public bool IsAdult => Age >= 18;
}

Accessing Properties

Once you have an object, you can access its properties using the dot operator:

csharp
Person person = new Person();
person.Name = "Alice"; // Set property
person.Age = 25; // Set property

Console.WriteLine($"Name: {person.Name}"); // Get property
Console.WriteLine($"Is Adult: {person.IsAdult}"); // Get computed property

Output:

Name: Alice
Is Adult: True

Calling Object Methods

Methods define the behavior of objects. They are called using the dot notation:

csharp
public class Calculator
{
public int Add(int a, int b)
{
return a + b;
}

public void DisplayResult(string operation, int result)
{
Console.WriteLine($"The result of {operation} is {result}");
}
}

// Using the methods
Calculator calc = new Calculator();
int sum = calc.Add(5, 3); // Calling a method that returns a value
calc.DisplayResult("addition", sum); // Calling a void method

Output:

The result of addition is 8

Value Types vs Reference Types

In .NET, objects can be either value types or reference types:

Value Types

Value types (derived from System.ValueType) store their data directly in memory where they're declared:

csharp
int number = 42;
DateTime date = DateTime.Now;
bool isActive = true;

Reference Types

Reference types store a reference (pointer) to the data in memory:

csharp
string name = "John";  // String is a reference type
Person person = new Person(); // Custom classes are reference types
List<int> numbers = new List<int> { 1, 2, 3 }; // Collections are reference types

Important Distinction

Understanding the difference is crucial:

csharp
// Value types
int a = 10;
int b = a; // Creates a copy of value
b = 20; // Only changes b, not a
Console.WriteLine($"a: {a}, b: {b}"); // Outputs: a: 10, b: 20

// Reference types
Person p1 = new Person { Name = "Alice" };
Person p2 = p1; // Both variables point to the same object
p2.Name = "Bob"; // Changes the name for both p1 and p2
Console.WriteLine($"p1.Name: {p1.Name}, p2.Name: {p2.Name}"); // Outputs: p1.Name: Bob, p2.Name: Bob

Null Reference and Nullable Types

Reference type variables can be null, indicating they don't refer to any object:

csharp
Person person = null;
// The following would cause a NullReferenceException at runtime
// Console.WriteLine(person.Name);

// Safe way to access properties of potentially null objects
string name = person?.Name ?? "Unknown";
Console.WriteLine(name); // Outputs: Unknown

Value types are normally non-nullable, but C# 2.0+ offers nullable value types:

csharp
int? nullableInt = null;
if (nullableInt.HasValue)
{
Console.WriteLine(nullableInt.Value);
}
else
{
Console.WriteLine("No value");
}

Common Object Operations

The Object Class Methods

All objects in .NET inherit from System.Object, which provides the following methods:

csharp
public class Product
{
public string Name { get; set; }
public decimal Price { get; set; }

// Override ToString() method
public override string ToString()
{
return $"{Name} - ${Price}";
}

// Override Equals() method
public override bool Equals(object? obj)
{
if (obj is not Product other)
return false;

return Name == other.Name && Price == other.Price;
}

// Override GetHashCode() method
public override int GetHashCode()
{
return HashCode.Combine(Name, Price);
}
}

// Usage example
Product p1 = new Product { Name = "Laptop", Price = 999.99m };
Product p2 = new Product { Name = "Laptop", Price = 999.99m };

Console.WriteLine(p1.ToString()); // Outputs: Laptop - $999.99
Console.WriteLine(p1.Equals(p2)); // Outputs: True
Console.WriteLine(p1.GetHashCode()); // Outputs: A hash code

Real-World Example: Building a Library System

Let's apply our knowledge of objects to build a simple library management system:

csharp
public class Book
{
public string Title { get; set; }
public string Author { get; set; }
public string ISBN { get; set; }
public bool IsAvailable { get; set; } = true;

public Book(string title, string author, string isbn)
{
Title = title;
Author = author;
ISBN = isbn;
}

public override string ToString()
{
return $"{Title} by {Author} (ISBN: {ISBN}) - {(IsAvailable ? "Available" : "Checked out")}";
}
}

public class Library
{
private List<Book> _books = new List<Book>();

public void AddBook(Book book)
{
_books.Add(book);
}

public Book? FindBook(string isbn)
{
return _books.FirstOrDefault(b => b.ISBN == isbn);
}

public bool CheckoutBook(string isbn)
{
Book? book = FindBook(isbn);
if (book != null && book.IsAvailable)
{
book.IsAvailable = false;
return true;
}
return false;
}

public bool ReturnBook(string isbn)
{
Book? book = FindBook(isbn);
if (book != null && !book.IsAvailable)
{
book.IsAvailable = true;
return true;
}
return false;
}

public List<Book> GetAvailableBooks()
{
return _books.Where(b => b.IsAvailable).ToList();
}
}

Let's see how we would use these classes:

csharp
// Create a library and add some books
Library library = new Library();

library.AddBook(new Book("The Great Gatsby", "F. Scott Fitzgerald", "9780743273565"));
library.AddBook(new Book("To Kill a Mockingbird", "Harper Lee", "9780061120084"));
library.AddBook(new Book("1984", "George Orwell", "9780451524935"));

// Display all available books
Console.WriteLine("Available books:");
foreach (var book in library.GetAvailableBooks())
{
Console.WriteLine(book);
}

// Checkout a book
string isbnToCheckout = "9780061120084";
if (library.CheckoutBook(isbnToCheckout))
{
Console.WriteLine($"\nBook with ISBN {isbnToCheckout} checked out successfully.");
}

// Display available books after checkout
Console.WriteLine("\nAvailable books after checkout:");
foreach (var book in library.GetAvailableBooks())
{
Console.WriteLine(book);
}

// Return the book
if (library.ReturnBook(isbnToCheckout))
{
Console.WriteLine($"\nBook with ISBN {isbnToCheckout} returned successfully.");
}

Output:

Available books:
The Great Gatsby by F. Scott Fitzgerald (ISBN: 9780743273565) - Available
To Kill a Mockingbird by Harper Lee (ISBN: 9780061120084) - Available
1984 by George Orwell (ISBN: 9780451524935) - Available

Book with ISBN 9780061120084 checked out successfully.

Available books after checkout:
The Great Gatsby by F. Scott Fitzgerald (ISBN: 9780743273565) - Available
1984 by George Orwell (ISBN: 9780451524935) - Available

Book with ISBN 9780061120084 returned successfully.

This example shows how objects interact with each other to model a real-world system. The Book objects maintain their state (availability) and the Library class manages a collection of books and operations on them.

Best Practices for Working with Objects

  1. Follow Encapsulation: Keep fields private and expose them through properties.

  2. Use Immutability When Possible: Consider making objects immutable (properties with only getters) for thread-safety and predictability.

  3. Override Object Methods When Necessary: Implement meaningful ToString(), Equals(), and GetHashCode() methods.

  4. Handle Null References: Check for null references before accessing properties or methods.

  5. Dispose of Resources: Implement IDisposable for objects that hold unmanaged resources.

  6. Use Object Initializers: They make code more readable and concise.

  7. Consider Record Types: C# 9.0+ offers record types for immutable data objects:

csharp
// C# 9.0+ record type - immutable data object with built-in equality
public record Person(string FirstName, string LastName, int Age);

// Usage
var person1 = new Person("John", "Doe", 30);
var person2 = new Person("John", "Doe", 30);
Console.WriteLine(person1 == person2); // Outputs: True (value equality)

Summary

Objects are the cornerstone of .NET programming, representing the building blocks that make up your applications. In this guide, we've explored:

  • What objects are in .NET and their key characteristics
  • How to create objects using different approaches
  • Working with object properties and methods
  • Value types vs. reference types
  • Nullable types and handling null references
  • Common operations that all objects inherit from System.Object
  • A real-world example using objects to build a library system
  • Best practices for working with objects

By understanding these concepts, you'll be well-equipped to design and build object-oriented applications in .NET.

Exercises

  1. Create a BankAccount class with properties for account number, balance, and account holder. Add methods for deposit and withdrawal that validate the operations.

  2. Build a Person class with properties for name, address, and date of birth. Add methods to calculate the person's age and to format their address.

  3. Create a ShoppingCart class that contains a list of Product objects. Add methods to add/remove products, calculate the total price, and apply discounts.

  4. Experiment with value equality by overriding Equals() and GetHashCode() for a custom class, then test it by adding instances to a HashSet<T>.

Additional Resources



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)