.NET Object Relationships

Understanding the relationships between objects is fundamental to building robust and maintainable .NET applications. These relationships define how classes interact and depend on each other.

Association

Association represents a relationship between two classes where one class knows about another. This is the most general form of relationship and can be one-to-one, one-to-many, many-to-one, or many-to-many.

In .NET, association is typically implemented through fields or properties that hold references to objects of other types.

Example: One-to-Many Association

A Department can have many Employee objects.


public class Employee
{
    public int EmployeeId { get; set; }
    public string Name { get; set; }
}

public class Department
{
    public string DepartmentName { get; set; }
    public List<Employee> Employees { get; set; } = new List<Employee>();

    public void AddEmployee(Employee employee)
    {
        Employees.Add(employee);
    }
}
                

Aggregation

Aggregation is a specialized form of association where one class (the whole) contains or is composed of other classes (the parts). However, the parts can exist independently of the whole.

Think of a Car and its Engine. The engine can exist on its own, but it's part of the car.

Example: Aggregation


public class Engine
{
    public string Type { get; set; }
}

public class Car
{
    public string Model { get; set; }
    public Engine Engine { get; set; } // Aggregation: Engine is part of Car, but could exist independently

    public Car(Engine engine)
    {
        Engine = engine;
    }
}
                

Composition

Composition is a stronger form of aggregation. Here, the part cannot exist independently of the whole. If the whole is destroyed, the parts are also destroyed.

Consider a Room and its Furniture. If the room is demolished, the furniture within it is also gone.

Example: Composition


public class Furniture
{
    public string Item { get; set; }
}

public class Room
{
    public string RoomName { get; set; }
    private List<Furniture> _furnitureItems = new List<Furniture>();

    public Room(string roomName)
    {
        RoomName = roomName;
    }

    public void AddFurniture(Furniture item)
    {
        _furnitureItems.Add(item);
    }

    // When Room is disposed, the furniture is effectively gone with it in this model.
}
                

Inheritance

Inheritance models an "is-a" relationship. A derived class (child) inherits properties and methods from a base class (parent). This promotes code reuse and establishes a hierarchy.

In C#, inheritance is achieved using the colon syntax (:).

Example: Inheritance


public class Vehicle
{
    public virtual void Drive()
    {
        Console.WriteLine("Driving the vehicle...");
    }
}

public class Car : Vehicle // Car "is a" Vehicle
{
    public override void Drive()
    {
        Console.WriteLine("Driving the car...");
    }
}

public class Motorcycle : Vehicle // Motorcycle "is a" Vehicle
{
    public override void Drive()
    {
        Console.WriteLine("Riding the motorcycle...");
    }
}
                

For more details on Inheritance, see the Inheritance documentation.

Dependency

Dependency occurs when a class uses another class in some way, typically as a parameter in a method, a local variable, or a static method call. The dependent class doesn't own or directly contain the dependency.

A class that sends an email depends on an email service.

Example: Dependency


public interface IEmailService
{
    void SendEmail(string to, string subject, string body);
}

public class NotificationService
{
    private readonly IEmailService _emailService;

    // Dependency injected via constructor
    public NotificationService(IEmailService emailService)
    {
        _emailService = emailService;
    }

    public void SendWelcomeEmail(string userEmail)
    {
        _emailService.SendEmail(userEmail, "Welcome!", "Thank you for joining!");
    }
}
                

Key Takeaways

  • Association: General "uses-a" relationship.
  • Aggregation: "has-a" where parts can be independent.
  • Composition: Stronger "has-a" where parts depend on the whole.
  • Inheritance: "is-a" relationship for code reuse and hierarchy.
  • Dependency: Using another class without ownership (e.g., via parameters).