Switch with Object Instances

18,352

Solution 1

To directly answer your question, make ModelType an enum and switch off that value. Have the Car type have a ModelType property called "Model" in the example below.

public enum ModelType
{
    Ferrari = 0,
    AstonMartin = 1
}

public int GetMaxSpeed( Car car )
{
    switch( car.Model )
    {
        case Ferrari:
           return 300;
        case AstonMartin:
           return 250;
        default:
           return 100;
    }
}

But the better question is, why aren't you using polymorphism? You can make Car a base type and have different models inherit from it. The base Car type should have a MaxSpeed property. No matter what subclass you have inheriting from Car, you can reference MaxSpeed to get the property value for that particular model. This might be over-complicating your example (homework?), but it would make your code more OOP.

public class Car
{
    private int _maxSpeed = 200;
    public int MaxSpeed
    {
        get { return _maxSpeed; }
        protected set { _maxSpeed = value; }
    }
}

public class Ferrari : Car
{
    public Ferrari()
    {
        // Constructor 
        this.MaxSpeed = 250;
    }
}

// client code
public void DoStuff()
{
   Car ferrari = new Ferrari();
   Console.WriteLine( ferrari.MaxSpeed );
}

If you want to have a Garage class with a list of cars, it would look something like the following. Keep in mind this is very crude code but it shows you what I'm talking about in the comments.

public class Garage
{
    private List<Car> Cars { get; set; }

    public Garage()
    {
       this.LoadCars();
    }

    private void LoadCars()
    {
       this.Cars = new List<Car>();
       this.Cars.Add( new Ferrari() );
       this.Cars.Add( new AstonMartin() );
    }

    public int GetMaxSpeedOfAllCars()
    {
        int maxSpeed = 0;

        foreach( Car car in this.Cars )
        {
            if( car.MaxSpeed > maxSpeed )
            {
                maxSpeed = car.MaxSpeed;
            }
        }

        return maxSpeed;
    }

}

Solution 2

It depends on what you want to do with it. If the "switch" is to give the cars extra behaviour, put it in the class itself. For example, in your case you've already got the appropriate field (ick, public fields, but...) You can just use:

public static int GetMaxSpeed(Car car)
{
    return car.MaxSpeed;
}

In other cases, you might give the type a method, and you can use nested classes to implement the methods differently based on the different values. Give the "base" class a private constructor and abstract methods, then create derived classes as nested classes so they can still use the private constructor and expose specific values. I call these types "smart enums".

If you want to map each value to another value, use a Dictionary<Car,string> (or whatever). If you want to map each value to an action, use a Dictionary<Car, Action>.

Basically you won't be able to use switch unless you have an enum or some integral type... and that would usually be a pain. Using a dictionary is often a simpler approach.

If you can give a more realistic example which isn't so easily solved, we can help more...

Solution 3

You won't be able to do this, because C# only supports compile-time constants for switch cases. Instead you should use if/else blocks.

Solution 4

I would, just on general principles, create a Dictionary of these instances (or just maintain a List) instead of switching on them. Switch statements are sometimes necessary, but they are rarely "SOLID" code; any time a new type of Car is created, you will have to change the switch statement to handle this new case.

static void Main(string[] args)
{
    Console.WriteLine(GetMaxSpeed(Car.Ferarri));
    Console.ReadLine();
}

public static int GetMaxSpeed(string ModelType)
{
    foreach(var car in Car.Cars)
       if(car.Name == ModelType)
          return car.MaxSpeed;
}

public enum Car
{
    public int MinSpeed;
    public int MaxSpeed;
    public string Name;

    public Car(string Name, int MinSpeed, int MaxSpeed)
    {
        this.Name = Name;
        this.MinSpeed = MinSpeed;
        this.MaxSpeed = MaxSpeed;
    }

    public static List<Car> Cars = new List<Car>
    {
       new Car(Car.Ferrari, 30, 240);
       new Car(Car.VW, 10, 50);
       new Car(Car.AstonMartin, 75, 180);        
    }

    public static const string Ferrari = "Ferrari";
    public static const string VW = "VW";
    public static const string AstonMartin= "AstonMartin";
}

If you simply had to switch on object references, try switching on a private integral-type field uniquely identifying that car; an ID field. Then, you can compare IDs within the switch statement instead of references.

static void Main(string[] args)
{
    Console.WriteLine(GetMaxSpeed(Car.Ferrari));
    Console.ReadLine();
}

public static int GetMaxSpeed(Car ModelType)
{
    switch (ModelType.Id)
    {
        case Car.Ferrari.Id:
            return Car.Ferrari.MaxSpeed;

        case Car.VW.Id:
            return Car.VW.MaxSpeed;

        case Car.AstonMartin.Id:
            return Car.AstonMartin.MaxSpeed;
    }
}

public class Car
{
    public int MinSpeed;
    public int MaxSpeed;
    internal int Id;

    public Car(int MinSpeed, int MaxSpeed)
    {
        this.MinSpeed = MinSpeed;
        this.MaxSpeed = MaxSpeed;
    }

    public static Car Ferrari = new Car(30, 240){Id = 1};
    public static Car VW = new Car(10, 50){Id = 2};
    public static Car AstonMartin = new Car(75, 180){Id = 3};
}
Share:
18,352
William
Author by

William

Updated on September 15, 2022

Comments

  • William
    William over 1 year

    Edit

    Here is a different version of the code that makes it a little more clear about what I am trying to do:

    class Program
    {
        static void Main(string[] args)
        {
            RepairCar(Car.Ferrari);
        }
    
        public static void RepairCar(Car BrokenCar)
        {
            switch (BrokenCar)
            {
                case Car.Ferrari:
                    Console.WriteLine("${0} of Insurance Needed", CalculateInsurance(BrokenCar));
                    // 
                    // Repair Algorithm Here
                    //
                    break;
    
                case Car.BMW:
                    Console.WriteLine("${0} of Insurance Needed", CalculateInsurance(BrokenCar));
                    // 
                    // Repair Algorithm Here
                    //
                    break;
    
                case Car.Audi:
                    Console.WriteLine("${0} of Insurance Needed", CalculateInsurance(BrokenCar));
                    // 
                    // Repair Algorithm Here
                    //
                    break;
    
                default:
                    Console.WriteLine("${0} of Insurance Needed", CalculateInsurance(BrokenCar));
                    // 
                    // Repair Algorithm Here
                    //
                    break;
            }
        }
    
        public static double CalculateInsurance(Car BrokenCar)
        {
            return (BrokenCar.Price / 10);
        }
    
    }
    
    public class Car
    {
        public double Price;
        public int MaxSpeed;
        public int MinSpeed;
    
        public Car(double Price, int MaxSpeed, int MinSpeed)
        {
            this.Price = Price;
            this.MaxSpeed = MaxSpeed;
            this.MinSpeed = MinSpeed;
        }
    
        public static Car Ferrari = new Car(100000, 250, 10);
        public static Car Audi = new Car(50000, 120, 30);
        public static Car BMW = new Car(35000, 80, 75);
    }
    

    As written, this won't compile because it will not let me switch the BrokenCar in the RepairCar method. Any suggestions?

    Original Post

    I am trying to create an object that can store static properties and, more importantly be able to be switched over - here is an example -

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(GetMaxSpeed(Car.Ferrari));
            Console.ReadLine();
        }
    
        public static int GetMaxSpeed(Car ModelType)
        {
            switch (ModelType)
            {
                case Car.Ferrari:
                    return Car.Ferrari.MaxSpeed;
    
                case Car.VW:
                    return Car.VW.MaxSpeed;
    
                case Car.AstonMartin:
                    return Car.AstonMartin.MaxSpeed;
            }
        }
    
        public class Car
        {
            public int MinSpeed;
            public int MaxSpeed;
    
            public Car(int MinSpeed, int MaxSpeed)
            {
                this.MinSpeed = MinSpeed;
                this.MaxSpeed = MaxSpeed;
            }
    
            public static Car Ferrari = new Car(30, 240);
            public static Car VW = new Car(10, 50);
            public static Car AstonMartin = new Car(75, 180);
        }
    
    }
    

    Does anyone have any ideas?

    EDIT

    This example describes a larger, more complex system. To illustrate why I would need to do it this way, see the following update:

        public static void OnCarSale(Car CarSold)
        {
            double LuxuryTax = 75;
    
            switch (CarSold)
            {
                case Car.Ferrari:
                    Console.WriteLine("Total Price: {0}", Car.Ferrari.Price + LuxuryTax);
                    break;
    
                case Car.VW:
                    Console.WriteLine("Total Price: {0}", Car.VW);
                    break;
    
                case Car.AstonMartin:
                    Console.WriteLine("Total Price: {0}", Car.Ferrari.Price + LuxuryTax);
                    break;
            }
        }
    

    This would get called by an event outside of this class.

  • KeithS
    KeithS over 12 years
    Ferrari and AstonMartin are not types; they are instances of the class Car. The is operator will not work here.
  • Jordan Parmer
    Jordan Parmer over 12 years
    Okay, I see what you mean now that I take a closer look. See my update, I added a better example using Polymorphism.
  • William
    William over 12 years
    The only issue with the second solution is that I am trying to have Ferrari be a static property of a larger object - Basically like if there was a Garage class which was passed in from an event and that Garage class had a static property called Car FirstCar and then I want to do a switch on FirstCar to determine whether it is a Ferrari, a VW or whatever -
  • William
    William over 12 years
    This would actually be perfect except when I try to do it it tells me that it won't work because switch expression must be based on a constant value -
  • Jordan Parmer
    Jordan Parmer over 12 years
    If you need a static property in a container class, just make the Car instance static inside of the container class and in the 'Get' return Car.MaxSpeed. It still works with polymorphism. But the enum approach is fine for this simple case. Pick whichever you feel like makes your implementation stronger in your scenario.
  • KeithS
    KeithS over 12 years
    You can try specifying the car as a const. This would work especially well if Car were a struct.
  • William
    William over 12 years
    but how will I be able to switch over the instances of Car?
  • Jordan Parmer
    Jordan Parmer over 12 years
    The garage can have a list of Car(s). So you would have: List<Car> declared on your Garage object (assuming that is where you want to put it). Then have a method that populates the list. Since each Car has a MaxSpeed property, you can iterate through the list calling MaxSpeed as well as ModelType to know what it is.
  • Jordan Parmer
    Jordan Parmer over 12 years
    See my updated post. I added a Garage class to show you what I'm talking about.
  • BlueRaja - Danny Pflughoeft
    BlueRaja - Danny Pflughoeft over 9 years
    This is the one thing Java does better than C# - in Java you can have enums with properties, methods, etc. In C# you can emulate that (with crappier syntax) using public readonly instances, but then you lose the ability to use switch...
  • Jon Skeet
    Jon Skeet over 9 years
    @BlueRaja-DannyPflughoeft: Yes, I quite agree (as I've said in various places :)
  • Rich
    Rich over 6 years