I've implemented a Vehicle service that is responsible for servicing vehicles such as cars and trucks:
public interface IVehicleService
{
void ServiceVehicle(Vehicle vehicle);
}
public class CarService : IVehicleService
{
void ServiceVehicle(Vehicle vehicle)
{
if (!(vehicle is Car))
throw new Exception("This service only services cars")
//logic to service the car goes here
}
}
I also have a vehicle service factory that is responsible for creating a vehicle service according to the type of vehicle passed in to the factory method:
public class VehicleServiceFactory
{
public IVehicleService GetVehicleService(Vehicle vehicle)
{
if (vehicle is Car)
{
return new CarService();
}
if (vehicle is Truck)
{
return new TruckService();
}
throw new NotSupportedException("Vehicle not supported");
}
}
The issue I had was with the CarService.ServiceVehicle
method. It's accepting a Vehicle
when ideally it should accept a Car
, as it knows that it will only service cars. So I decided to update this implementation to use generics instead:
public interface IVehicleService<T> where T : Vehicle
{
void ServiceVehicle(T vehicle);
}
public class CarService : IVehicleService<Car>
{
void ServiceVehicle(Car vehicle)
{
//this is better as we no longer need to check if vehicle is a car
//logic to service the car goes here
}
}
public class VehicleServiceFactory
{
public IVehicleService<T> GetVehicleService<T>(T vehicle) where T : Vehicle
{
if (vehicle is Car)
{
return new CarService() as IVehicleService<T>;
}
if (vehicle is Truck)
{
return new TruckService() as IVehicleService<T>;
}
throw new NotSupportedException("Vehicle not supported");
}
}
The issue I currently have is when calling this factory as follows:
var factory = new VehicleServiceFactory();
Vehicle vehicle = GetVehicle();
var vehicleService = factory.GetVehicleService(vehicle); // this returns null!
vehicleService.ServiceVehicle(vehicle);
GetVehicleService
returns null
, I guess because I'm passing in the base type Vehicle
into this method, so T
would evaluate to Vehicle
and it isn't possible to cast from CarService
(which implements IVehicleService<Car>
) to the effective return type which would be IVehicleService<Vehicle>
(please correct me if I'm wrong).
Would appreciate some guidance on how to resolve this.
T
isVechicle
so the as cast toIVehicleService<Vechicle>
fails and returnsnull
. – Phytographyas IVehcileService<T>
from your return statements? @Phytography So I noticed afterwards, hence I removed my comment. Question remains, what doesGetVehicle()
return? – HidalgoCarService
andTruckService
can be cast to, and for good reason. Simply put aIVehicleService<Car>
is not aIVehicleService<Vehicle>
– PhytographyVehicle
or it's being implicitly cast toVehicle
. – PhytographyCar
or aTruck
– Polyhymniaas
without checking the result. Doing this leads to mysterious null reference exceptions, just like this. If you mean to say "this thing really is of this type", then just cast it - at least then when it fails you get an invalid cast exception exactly where it occurs rather than a hard to debug null reference exception at a different location. – Circumfluent