1

I have to write a class called Vehicle with many attributes (e.g. size, seats, color, ...) and also I have two more classes to write called Trunk and Car with their own attributes.

So I wrote it:

// Vehicle.cs
abstract public class Vehicle
{
    public string Key { get; set; }
    ...
}

// Car.cs
public class Car : Vehicle
{
    ...
}

// Trunk.cs
public class Trunk : Vehicle
{
    ...
}

After that, I wrote an Interface:

// IVehicleRepository.cs
public interface IVehicleRepository
{
    void Add(Vehicle item);
    IEnumerable<Vehicle> GetAll();
    Vehicle Find(string key);
    Vehicle Remove(string key);
    void Update(Vehicle item);
}

So I was thinking that I could use something like this:

// CarRepository.cs
public class CarRepository : IVehicleRepository
{
    private static ConcurrentDictionary<string, Car> _cars =
          new ConcurrentDictionary<string, Car>();

    public CarRepository()
    {
        Add(new Car { seats = 5 });
    }

    public IEnumerable<Car> GetAll()
    {
        return _cars.Values;
    }

    // ... I implemented the other methods here

}

But, I got errors:

error CS0738: 'CarRepository' does not implement interface member 'IVehicleRepository.GetAll()'. 'CarRepository.GetAll()' cannot implement 'IVehicleRepository.GetAll()' because it does not have the matching return type of 'IEnumerable<'Vehicle>'.

So, how I can do it?

Chris Pickford
  • 8,642
  • 5
  • 42
  • 73

2 Answers2

6

Your CarRepository isn't implementing the method. These two are not the same:

  • public IEnumerable<Car> GetAll()
  • IEnumerable<Vehicle> GetAll()

These are two different types and when you derive from the interface you have to implement it exactly. You can just implement it this way:

public IEnumerable<Vehicle> GetAll()
{
    // Cast your car collection into a collection of vehicles
}

However the better way would be to make it a generic interface of: (The downside is that the two different implementations type again are two different types so see if that is what you want)

public interface IVehicleRepository<TVehicle> {}
public class CarRepository : IVehicleRepository<Car> {}

A more complete version:

public interface IVehicleRepository<TVehicle>  where TVehicle : Vehicle
{
    void Add(TVehicle item);
    IEnumerable<TVehicle> GetAll();
    Vehicle Find(string key);
    Vehicle Remove(string key);
    void Update(TVehicle item);
}

public class CarRepository : IVehicleRepository<Car>
{
    private static ConcurrentDictionary<string, Car> _cars =
          new ConcurrentDictionary<string, Car>();

    public CarRepository()
    {
        Add(new Car { seats = 5 });
    }

    public IEnumerable<Car> GetAll()
    {
        return _cars.Values;
    }
}
Gilad Green
  • 36,708
  • 7
  • 61
  • 95
  • Thank you, guys (http://stackoverflow.com/users/6400526/gilad-green and http://stackoverflow.com/users/5528593/ren%C3%A9-vogt). This helped me, but I got another problem. If I have just one repository I could inject it in "public void ConfigureServices(IServiceCollection services)" on Startup.cs: services.AddSingleton(); But, now I have two repositories: CarRepository and TrunkRepository (extending IVehicleRepository). How can I inject CarRepository and TrunkRepository now? –  Feb 03 '17 at 18:53
  • @Olavo Shibate - glad it helped. If it helped you solve the specific problem please consider marking as solved. As for the other question - the policy is that follow up questions should be posted in a separate question. Please search for similar problems people had and it you still need help please post a new question and we will be glad to help – Gilad Green Feb 03 '17 at 18:57
1

You could make the IVehicleRepository generic:

public interface IVehicleRepository<T> where T : Vehicle
{
    void Add(T item);
    IEnumerable<T> GetAll();
    Vehicle Find(string key);
    Vehicle Remove(string key);
    void Update(T item);
}

and then implement the classes like this:

public class CarRepository : IVehicleRepository<Car>
{
    private static ConcurrentDictionary<string, Car> _cars =
          new ConcurrentDictionary<string, Car>();

    public CarRepository()
    {
        Add(new Car { seats = 5 });
    }

    public IEnumerable<Car> GetAll()
    {
        return _cars.Values;
    }
}

But you will then still have the problem that a CarRepository is a IVehicleRepository<Car> while a TruckRepository would be a IVehicleRepository<Truck>. And these two interfaces are different types and only assignable to each other if the have the correct variance.

Community
  • 1
  • 1
René Vogt
  • 43,056
  • 14
  • 77
  • 99