Well, while I don't have a solution to how to make it work yet, (at least not in full), I think I now understand the problem. One of my initial assumptions appears to have been incorrect. I was under the impression that a less specific return type on an interface could be fulfilled by a more specific type. ie, an interface defining SomeBaseClass as a return type for a method can not be implemented by a class that implements the method returning SomeChildClass where SomeChildClass inherits from SomeBaseClass.
The use of covariant generics (via the out keyword) does provide some manner of ability to circumvent this by allowing the interface to be generically defined, however for my purposes, this falls apart when I hit results that need to be IList based (which requires an invariant type parameter).
Ultimately, the best it appears that can be done is that I can make it so that CarFactory only understands that it is working with a vehicle (by removing the additional where condition on the TVehicle generic parameter), requiring a cast within CarFactory, however when ever CarCompany instantiates CarFactory, it can still make it as CarFactory and the client code itself will not have to worry about a cast.
It's not ideal, but I think it may be the best possible due to C#'s lack of covariant return types.
interface IVehicleFactory<TVehicle> where TVehicle:Vehicle
{
TVehicle SomeMethod();
}
VehicleFactory<TVehicle> : IVehilceFactory<TVehicle> where TVehicle:Vehicle
{
TVehicle SomeMethod()
{
}
}
CarFactory<TVehicle> : IVehicleFactory<TVehicle> where TVehicle:Vehicle
{
TVehicle SomeMethod()
{
~~Always returns car and uses cast from Vehicle when necessary.
}
}
class VehicleFactory<TVehicle>
{
static IVehicleFactory<TVehicle> CreateContextSpecificFactory()
{
if(someCondition)
{
return new CarFactory<TVehicle>;
}
}
}
class CarCompany
{
CarFactory<Car> carFactory = new CarFactory<Car>;
Car car = carFactory.SomeMethod();
}
class VehicleCompany
{
VehicleFactory<Vehicle> vehicleFactory = VehicleFactory<Vehicle>.CreateContextSpecificFactory();
}