Reputation: 908
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
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
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
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
Reputation: 2263
you can write this:
((Car)vehicle).Engine = "what you want";
simply you are casting the object when needed.
Upvotes: -2
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