Ashkan Hovold
Ashkan Hovold

Reputation: 908

Accessing properties on class when working with interface

I did this little console application to illustrate my problem.

I wonder if there is a way to access the properties on the class which is the current implementation of the interface you are working on. In this example below I would like to set the vehicle interface property Engine if it is a car. I found a way to do this using the brackets when you are doing a new instance of car, but I would like to do this later by doing vehicle.Engine = "something";

namespace ConsoleApplication1
{
class Program
{
    static void Main(string[] args)
    {
        var car = (Car)GetVehicle(VehicleType.Car);

        var bike = (Bike)GetVehicle(VehicleType.Bike);

        Console.ReadKey();
    }



    static IVehicle GetVehicle(VehicleType type)
    {
        IVehicle vehicle = null;

        switch (type)
        {
            case VehicleType.Car:
                vehicle = new Car() { Engine = "V8", Name = "Car Name" };//Works
                vehicle.Engine = "cannot do this"; //This does not work
                break;
            case VehicleType.Bike:
                vehicle = new Bike() { Mountainbike = true, Name = "Bike name" }; // Works
                vehicle.Mountaikbike = true; //This does not work either, same problem
                break;
            default:
                break;
        }

        return vehicle;
    }


}


public enum VehicleType
{
    Car, Bike
}


public class Car : IVehicle
{
    public string Name { get; set; }
    public string Engine { get; set; }

}

public class Bike : IVehicle
{
    public string Name { get; set; }
    public bool Mountainbike { get; set; }
}

public interface IVehicle
{
    string Name { get; set; }
}

}

Upvotes: 2

Views: 225

Answers (5)

haim770
haim770

Reputation: 49133

Even though your GetVehicle() method returns an IVechile, it doesn't mean that internally it has to refer to the returned object as IVechile as well. It can definitely refer to it as the actual (concrete) type and then having the ability to access its public properties as usual.

So you can simply do this:

static IVehicle GetVehicle(VehicleType type)
{
    IVehicle ret = null;

    switch (type)
    {
        case VehicleType.Car:
            var car = new Car() { Name = "Car Name" };
            car.Engine = "V8";
            ret = car;
            break;
        case VehicleType.Bike:
            var bike = new Bike() { Name = "Bike name" }; 
            bike.Mountainbike = true;
            ret = bike;
            break;
    }

    return ret;
}

Or even shorter:

static IVehicle GetVehicle(VehicleType type)
{
    switch (type)
    {
        case VehicleType.Car:
            return new Car() { Engine = "V8", Name = "Car Name" };
        case VehicleType.Bike:
            return new Bike() { Mountainbike = true, Name = "Bike name" }; 
    }

    return null;
}

Upvotes: 3

Raja Nadar
Raja Nadar

Reputation: 9499

To answer the question of how to do it later, if you have code like

IVehicle vehicle= GetVehicle(VehicleType.Car);

// cast car 
Car car = vehicle as Car;

if (car != null)
{
 car.Engine = "V8";
}

basically IVehicle does not have 'Engine' as a property. it is something a Car type added. Hence you need to cast your IVehicle to Car and check if it is really a car. If it is, then you set it.

And if you think that a lot of your vehicles would need Engine, then you can do:

public interface IVehicleWithEngine :IVehicle
{
 string Engine { get; set; }
}

and make Car and other 'Engine' based vehciles implement it.

Upvotes: 2

James Lucas
James Lucas

Reputation: 2522

This is known as 'leaky abstraction' and shouldn't be done: ((Car)vehicle).Engine = "...". Your code should deal in contracts (interfaces) not in concrete implementations (classes).

In this instance you should create an ICar interface that extends IVehicle and use it to expose the Engine property and test if your IVehicle exposes ICar. This way many things can be treated as IVehicle and ICar is a specialization that can be handled more specifically.

Upvotes: 3

pinturic
pinturic

Reputation: 2263

you can write this:

((Car)vehicle).Engine = "what you want";

simply you are casting the object when needed.

Upvotes: -2

Sayse
Sayse

Reputation: 43330

The problem is caused by where you are initiating the vehicle, you can just return from the switch since that is all you are doing in the method.

switch (type)
{
    case VehicleType.Car:
        return new Car() { Engine = "V8", Name = "Car Name" };
        break;
    case VehicleType.Bike:
        return new Bike() { Mountainbike = true, Name = "Bike name" }; 
        break;
    default:
        break;
}
return null;

Upvotes: 1

Related Questions