C# Interface Basics - Fundamentals
Understanding Interface Basics
Interfaces in C# are reference types that define a contract consisting of members that implementing classes must provide. Unlike classes, interfaces cannot be instantiated directly and typically contain no implementation details for their members (except for default implementations introduced in C# 8.0).
The primary purpose of interfaces is to define capabilities that classes can implement, enabling polymorphism without the limitations of single inheritance. Interfaces help create loosely coupled, testable, and maintainable code.
Basic Interface Syntax and Implementation
Interfaces are defined using the interface keyword and can contain methods, properties, events, and indexers. All interface members are implicitly public and abstract, and must be implemented by any class or struct that implements the interface.
using System;
// Basic interface with different member types
public interface IVehicle
{
// Property
string Make { get; set; }
string Model { get; set; }
// Method
void Start();
void Stop();
// Read-only property
bool IsRunning { get; }
}
// Interface with events
public interface IAlertable
{
event Action<string> OnAlert;
void TriggerAlert(string message);
}
// Class implementing multiple interfaces
public class Car : IVehicle, IAlertable
{
public string Make { get; set; }
public string Model { get; set; }
public bool IsRunning { get; private set; }
// Event implementation
public event Action<string> OnAlert;
public Car(string make, string model)
{
Make = make;
Model = model;
IsRunning = false;
}
public void Start()
{
if (!IsRunning)
{
IsRunning = true;
Console.WriteLine($"{Make} {Model} started");
TriggerAlert("Vehicle started");
}
}
public void Stop()
{
if (IsRunning)
{
IsRunning = false;
Console.WriteLine($"{Make} {Model} stopped");
TriggerAlert("Vehicle stopped");
}
}
public void TriggerAlert(string message)
{
OnAlert?.Invoke(message);
}
// Additional method not in interface
public void Honk()
{
Console.WriteLine("Beep! Beep!");
TriggerAlert("Horn sounded");
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("=== Interface Basics Demo ===");
Car car = new Car("Toyota", "Camry");
// Subscribe to event
car.OnAlert += (message) =>
{
Console.WriteLine($"ALERT: {message}");
};
// Use IVehicle functionality
IVehicle vehicle = car;
vehicle.Start();
Console.WriteLine($"Is running: {vehicle.IsRunning}");
// Use IAlertable functionality
IAlertable alertable = car;
alertable.TriggerAlert("Manual alert");
// Use Car-specific functionality
car.Honk();
vehicle.Stop();
Console.WriteLine($"Is running: {vehicle.IsRunning}");
// Interface type checking
Console.WriteLine("\n=== Type Checking ===");
Console.WriteLine($"Car is IVehicle: {car is IVehicle}");
Console.WriteLine($"Car is IAlertable: {car is IAlertable}");
Console.WriteLine($"Vehicle type: {vehicle.GetType()}");
}
}
=== Interface Basics Demo === Toyota Camry started ALERT: Vehicle started Is running: True ALERT: Manual alert Beep! Beep! ALERT: Horn sounded Toyota Camry stopped ALERT: Vehicle stopped Is running: False === Type Checking === Car is IVehicle: True Car is IAlertable: True Vehicle type: Car
Interface Properties and Indexers
Interfaces can define properties and indexers that implementing classes must provide. Interface properties can be read-only, write-only, or read-write. Indexers in interfaces allow implementing classes to support array-like access to elements.
using System;
using System.Collections.Generic;
// Interface with properties
public interface IProduct
{
string Name { get; set; }
decimal Price { get; }
string Description { set; }
int Stock { get; set; }
}
// Interface with indexer
public interface IInventory
{
IProduct this[int index] { get; set; }
int Count { get; }
void AddProduct(IProduct product);
}
// Implementation class
public class Product : IProduct
{
public string Name { get; set; }
public decimal Price { get; private set; }
private string description;
public string Description
{
set { description = value; }
}
public int Stock { get; set; }
public Product(string name, decimal price, int stock)
{
Name = name;
Price = price;
Stock = stock;
}
public string GetDescription() => description;
}
public class StoreInventory : IInventory
{
private List<IProduct> products = new List<IProduct>();
public IProduct this[int index]
{
get => products[index];
set => products[index] = value;
}
public int Count => products.Count;
public void AddProduct(IProduct product)
{
products.Add(product);
}
public void DisplayInventory()
{
Console.WriteLine("Store Inventory:");
for (int i = 0; i < products.Count; i++)
{
Console.WriteLine($"{i + 1}. {products[i].Name} - ${products[i].Price} (Stock: {products[i].Stock})");
}
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("=== Interface Properties and Indexers ===");
Product product1 = new Product("Laptop", 999.99m, 10);
product1.Description = "High-performance gaming laptop";
Product product2 = new Product("Mouse", 25.50m, 50);
product2.Description = "Wireless optical mouse";
StoreInventory inventory = new StoreInventory();
inventory.AddProduct(product1);
inventory.AddProduct(product2);
inventory.DisplayInventory();
Console.WriteLine("\n=== Using Indexer ===");
IProduct firstProduct = inventory[0];
Console.WriteLine($"First product: {firstProduct.Name}");
Product newProduct = new Product("Keyboard", 75.00m, 25);
inventory[1] = newProduct;
Console.WriteLine("\nAfter modification:");
inventory.DisplayInventory();
Console.WriteLine("\n=== Property Access Demo ===");
Console.WriteLine($"Product 1 stock: {product1.Stock}");
product1.Stock = 15;
Console.WriteLine($"Product 1 stock after update: {product1.Stock}");
}
}
=== Interface Properties and Indexers === Store Inventory: 1. Laptop - $999.99 (Stock: 10) 2. Mouse - $25.50 (Stock: 50) === Using Indexer === First product: Laptop After modification: Store Inventory: 1. Laptop - $999.99 (Stock: 10) 2. Keyboard - $75.00 (Stock: 25) === Property Access Demo === Product 1 stock: 10 Product 1 stock after update: 15