Mike Bryant
Mike Bryant

Reputation: 107

c# OO advice for inherited attribute classes

I would like to get some OO correct advice please. What is the correct way of accessing attribute data from inherited classes.

Assuming 3 classes:

public abstract class Vehicle
{
  public int Id {get; set; }    
  public int Wheels {get; set; }
  public string Name {get; set; }
  public string Color {get; set; }
 }
 public class Car : Vehicle
 {
 }
 public class Truck : Vehicle
 {
  public int LoadCapacity {get; set; }  
 }

My first thought was to create a repository of some kind that gives me the attributes of whatever I'm looking for.

There are 2 types of queries as I see it that I will need:

  1. Return attributes of vehicle with a specific ID
  2. Give me all vehiclesof a specific type

So:

public class VehicleRepository
{
    ICollection <???> _vehicles;

    ??? GetVehicle(int Id);
    ??? GetVehicles(??? vehicleType);
}

The ??? are my unknowns.

My thought was to add something like an interface for IVehicle and implement Vehicle with it. The result would be something like:

public class VehicleRepository
{
    ICollection <IVehicle> _vehicles;

    IVehicle GetVehicle(int Id);
    ICollection <IVehicle> GetVehicles(IVehicle vehicleType);
}

This obviously doesnt work.

public IVehicle GetVehicle(int Id)
{
    return _vehicles.First(x=>x.Id == Id);
    // The above want compile as the interface has no attributes
}

If I use Vehicle instead of IVehicle, the 'First(x=>x.Id == Id)' will work fine but it will not return 'LoadCapacity' if the vehicle is a truck.

Looking at the GetVehicles function, I was thinking something like:

public ICollection <T> GetVehicles <T> ()
{
    var vehicles = _vehicles.Where(???);
    return vehicles;
}

A bit lost on what should go in there BUT I would like to avoid reflection and just reading assemblies and class types, etc.

Thanks for any advice.

Upvotes: 3

Views: 168

Answers (2)

sircodesalot
sircodesalot

Reputation: 11439

To store and get vericles, all you would need to do is something like:

class VehicleRepository {
    List<Vehicle> vehicles;
}

to retrieve them, simply use IEnumerable<T>.OfType<U>():

VehicleRepository repository = ...
repository.vehicles.OfType<Car>(); // This will get you all of the cars
repository.vehicles.OfType<Truck>(); // This will get you all of the trucks

If you wanted to get fancy though, you could make the VehicleRepository a collection all its own by making it implement IEnumerable<T>. Consider:

class VehicleRepository : IEnumerable<Vehicle> {
    List<Vehicle> vehicles;

    public IEnumerator<Vehicle> GetEnumerator() {
        return vehicles.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
        return this.GetEnumerator();
    }
}

Then you can query against the collection itself, as in:

public static void Main() {
    VehicleRepository repository = ...;

    // Notice that we skip accessing the vehicles member
    // because by implementing IEnumerable<T> this class
    // becomes a collection. Now you can use OfType<T> directly.
    repository.OfType<Car>(); 
}

EDIT: To do something like GetVehicleByID, you might try something like this:

class VehicleRepository : IEnumerable<Vehicle> {
    List<Vehicle> vehicles;

    public Vehicle GetVehicleByID(Int32 id) {
        return vehicles[id];
    }
}

you could also use an indexer, like so:

class VehicleRepository : IEnumerable<Vehicle> {
    List<Vehicle> vehicles;

    public Vehicle this[Int32 id] {
        get { return vehicles[id]; }
    }
}

To get LoadCapacity from a truck, all you would have to do is something like this:

public static void Main() {
   VehicleRepository repository = ...

   // Assuming index zero is a truck
   Truck truck = (Truck)repository.GetVehicleByID(0);
   truck.LoadCapacity = ...
}

One cheaty way to get all items of a particular type (when bound to the UI, i.e. assuming you're using Strings) without using reflection is to match the ToString values of the Type names. For example:

public static void Main() {
   VehicleRepository repository = ...

   // Assume we're storing off the typename in the UI dropdown.
   // so that when the user selects it, we automatically have the correct
   // type name we want to filter by.
   String truckTypeName = typeof(Truck).GetType().ToString();      

   // Filter only by those types with a matching type name. Inefficient,
   // but it does avoid reflection.
   repository.Where(vehicle => vehicle.GetType().ToString() == truckTypeName)
}

Upvotes: 3

Guffa
Guffa

Reputation: 700322

You can use the OfType method to get the items in a collection of a specific type:

public ICollection<T> GetVehicles<T>() {
  return _vehicles.OfType<T>();
}

Upvotes: 0

Related Questions