Keywords: C# Programming | List Collections | Object-Oriented Design | Vehicle Management System | Batch Operations
Abstract: This article provides an in-depth exploration of using List collections to manage multiple vehicle objects in C# applications. Through analysis of a vehicle inventory management system code example, we demonstrate how to fix design flaws in the original code, including code duplication, incorrect inheritance relationships, and single-instance limitations. The article details basic List operations, usage of the AddRange method, and optimization of code structure through object-oriented design principles. Additionally, we provide complete refactored code examples showing how to implement multi-vehicle addition, search, and display functionality.
Problem Analysis
In the original code, several key design issues prevent effective management of multiple vehicle objects. First, the code maintains only one instance variable for each vehicle type (car, motorbike, truck), making it impossible to store information for multiple vehicles of the same type. Second, although List-related helper methods are defined, they are not properly utilized in the main logic.
List Collection Fundamentals
In C#, List<T> is a generic collection class in the System.Collections.Generic namespace used to store and manage groups of objects of the same type. Unlike arrays, Lists can dynamically resize and provide rich methods for adding, removing, and accessing elements.
Basic syntax for creating and initializing a List:
List<Vehicle> vehicles = new List<Vehicle>();
Adding a single element:
vehicles.Add(new Vehicle("Toyota", "Camry", "Blue"));
Using AddRange for Batch Operations
The AddRange method allows adding multiple elements to a List at once, which is more efficient than calling the Add method in a loop. This method accepts any collection that implements the IEnumerable<T> interface.
Example code:
List<Motorbike> bikes = new List<Motorbike>();
bikes.AddRange(new List<Motorbike>
{
new Motorbike("Honda", "CBR", "Red"),
new Motorbike("Yamaha", "R1", "Blue"),
new Motorbike("Kawasaki", "Ninja", "Green")
});
Code Refactoring and Optimization
Based on best practices, we have comprehensively refactored the original code:
First, define a unified base class:
public abstract class Vehicle
{
public string Make { get; set; }
public string Model { get; set; }
public string Colour { get; set; }
protected Vehicle(string make, string model, string colour)
{
Make = make;
Model = model;
Colour = colour;
}
}
Specific vehicle classes inherit from the base class:
public class Car : Vehicle
{
public Car(string make, string model, string colour)
: base(make, model, colour) { }
}
public class Motorbike : Vehicle
{
public Motorbike(string make, string model, string colour)
: base(make, model, colour) { }
}
public class Truck : Vehicle
{
public Truck(string make, string model, string colour)
: base(make, model, colour) { }
}
Implementing Multi-Vehicle Management
In the main program, we use Lists to manage multiple vehicles of each type:
class Program
{
private static List<Car> cars = new List<Car>();
private static List<Motorbike> bikes = new List<Motorbike>();
private static List<Truck> trucks = new List<Truck>();
static void Main()
{
int choice = 0;
while (choice != 5)
{
DisplayMenu();
choice = GetValidChoice();
switch (choice)
{
case 1:
AddVehicle(cars, "car");
break;
case 2:
AddVehicle(bikes, "motorbike");
break;
case 3:
AddVehicle(trucks, "truck");
break;
case 4:
SearchVehicles();
break;
case 5:
Console.WriteLine("Exiting program...");
break;
default:
Console.WriteLine("Invalid selection");
break;
}
}
}
}
Implementing Batch Addition Functionality
Using generic methods to implement unified vehicle addition logic:
private static void AddVehicle<T>(List<T> vehicleList, string vehicleType) where T : Vehicle
{
Console.WriteLine($"Adding new {vehicleType}:");
Console.Write("Enter make: ");
string make = Console.ReadLine();
Console.Write("Enter model: ");
string model = Console.ReadLine();
Console.Write("Enter colour: ");
string colour = Console.ReadLine();
T newVehicle = (T)Activator.CreateInstance(typeof(T), make, model, colour);
vehicleList.Add(newVehicle);
Console.WriteLine($"{vehicleType} added successfully!\n");
}
Search and Display Functionality
Implementing unified search and display logic:
private static void SearchVehicles()
{
Console.WriteLine("Select vehicle type to search (car/motorbike/truck):");
string searchType = Console.ReadLine().ToLower();
switch (searchType)
{
case "car":
DisplayVehicles(cars, "Cars");
break;
case "motorbike":
DisplayVehicles(bikes, "Motorbikes");
break;
case "truck":
DisplayVehicles(trucks, "Trucks");
break;
default:
Console.WriteLine("Invalid vehicle type");
break;
}
}
private static void DisplayVehicles<T>(List<T> vehicles, string vehicleType) where T : Vehicle
{
if (vehicles.Count == 0)
{
Console.WriteLine($"No {vehicleType.ToLower()} in inventory.\n");
return;
}
Console.WriteLine($"\n{vehicleType} in inventory:");
foreach (var vehicle in vehicles)
{
Console.WriteLine($" - {vehicle.Make} {vehicle.Model} ({vehicle.Colour})");
}
Console.WriteLine();
}
Other List Operation Methods
Besides AddRange, C#'s List provides other useful batch operation methods:
Using Concat method to merge lists:
List<string> firstList = new List<string> { "One", "Two", "Three" };
List<string> secondList = new List<string> { "Four", "Five" };
var combinedList = firstList.Concat(secondList).ToList();
Using InsertRange to insert multiple elements at a specified position:
List<int> numbers = new List<int> { 1, 2, 5, 6 };
numbers.InsertRange(2, new List<int> { 3, 4 });
// Result: 1, 2, 3, 4, 5, 6
Performance Considerations
When adding large numbers of elements, the AddRange method is generally more efficient than calling Add in a loop because the List can pre-allocate sufficient capacity internally. If you know in advance how many elements you will add, consider setting the List's initial capacity:
List<Vehicle> vehicles = new List<Vehicle>(100); // Initial capacity of 100
Error Handling and Input Validation
In practical applications, appropriate error handling should be added:
private static int GetValidChoice()
{
while (true)
{
if (int.TryParse(Console.ReadLine(), out int choice) && choice >= 1 && choice <= 5)
{
return choice;
}
Console.WriteLine("Please enter a valid number between 1 and 5");
}
}
Conclusion
By using List collections and object-oriented design principles, we have successfully resolved the original code's inability to manage multiple vehicle objects. Key improvements include: using generic Lists to store multiple objects, implementing unified base classes and inheritance structures, providing batch operation methods, and enhancing user interaction experience. This design not only solves the current problem but also provides a solid foundation for future feature expansion.