locked
Generic Factories and Inference RRS feed

  • Question

  • User631596016 posted

    abstract class Vehicle;
    abstract class Car : Vehicle;
    abstract class Plane : Vehicle;
    
    concrete class Toyota : Car;
    concrete class Benz : Car;
    concrete class Boeing : Plane;
    
    class VehicleFactory<TVehicleType>
    {
        public static TVehicleType CreatePlane<TVehicleType>() where TVehicleType : Plane
        {}
    
        public static TVehicleType CreateCar<TVehicleType>() where TVehicleType : Car
        {}
    }
    
    


    Is this the correct way? I'd like to be able to instantiate planes/cars like this:

    Boeing myPlane = VehicleFactory<Boeing>.CreatePlane();
    Benz myCar = VehicleFactory<Benz>.CreateCar();


    But with the factory I provided above I get "Cannot be inferred from usage" errors.

    How can I define the generic return type on the class but constrain it per a function? Or is this the wrong way to think about it? Should I have a PlaneFactory and a CarFactory?

    My issue is the difference between those two methods is small, and I'd like to have them call a private method that does heavy lifting than return for some final car/plane specific bits.

    Wednesday, June 2, 2010 1:31 PM

Answers

  • User-952121411 posted

     where TVehicleType : Plane   
     

    I have not used this notation (especially since I do VB.NET mostly) to directly instantiate based on the argument value to the factory.  Typically in deciding which type to return, a simple 'If' statement will work.  Can you try going the simple route just to get the code working, and then the C# folks can chime in as to the syntax you are using -

    //somthing like the following
    if (TVehicleType is Plane)
    {
       //Return concrete type
    }
    elseif(TVehicleType is Car)
    {
      //Return concrete type
    }


     

     

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, June 2, 2010 2:44 PM
  • User-2004844803 posted

    well, I tested it and with just one modification I got it to work. The VehicleFactory dont need the type, only the methods need them.


    public abstract class Vehicle { }
        public abstract class Car : Vehicle { }
        public abstract class Plane : Vehicle { }
    
        public class Toyota : Car { }
        public class Benz : Car { }
        public class Boeing : Plane { }
    
        public class VehicleFactory
        {
            public static TVehicleType CreatePlane<TVehicleType>() where TVehicleType : Plane
            {
                Plane o = new Boeing();
                return (TVehicleType)o;
            }
    
            public static TVehicleType CreateCar<TVehicleType>() where TVehicleType : Car
            {
                Car c = new Benz();
                return (TVehicleType)c;
            }
        }

    Boeing myPlane = VehicleFactory.CreatePlane<Boeing>();
    Benz myCar = VehicleFactory.CreateCar<Benz>();





    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, June 2, 2010 2:47 PM
  • User-2004844803 posted

    ok, you will have an abstract method "GenarateSeats" on your vehicle class with different implementations in both Plane and Car that you will call from your factory? That seems logical to me but I can figure out if it follows any specific pattern. But sure, thats the way to do it.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, June 3, 2010 1:19 AM

All replies

  • User-952121411 posted

     where TVehicleType : Plane   
     

    I have not used this notation (especially since I do VB.NET mostly) to directly instantiate based on the argument value to the factory.  Typically in deciding which type to return, a simple 'If' statement will work.  Can you try going the simple route just to get the code working, and then the C# folks can chime in as to the syntax you are using -

    //somthing like the following
    if (TVehicleType is Plane)
    {
       //Return concrete type
    }
    elseif(TVehicleType is Car)
    {
      //Return concrete type
    }


     

     

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, June 2, 2010 2:44 PM
  • User-2004844803 posted

    well, I tested it and with just one modification I got it to work. The VehicleFactory dont need the type, only the methods need them.


    public abstract class Vehicle { }
        public abstract class Car : Vehicle { }
        public abstract class Plane : Vehicle { }
    
        public class Toyota : Car { }
        public class Benz : Car { }
        public class Boeing : Plane { }
    
        public class VehicleFactory
        {
            public static TVehicleType CreatePlane<TVehicleType>() where TVehicleType : Plane
            {
                Plane o = new Boeing();
                return (TVehicleType)o;
            }
    
            public static TVehicleType CreateCar<TVehicleType>() where TVehicleType : Car
            {
                Car c = new Benz();
                return (TVehicleType)c;
            }
        }

    Boeing myPlane = VehicleFactory.CreatePlane<Boeing>();
    Benz myCar = VehicleFactory.CreateCar<Benz>();





    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, June 2, 2010 2:47 PM
  • User631596016 posted

    Thank you both for the timely replies!

    @atconway: I can do that, and indeed it was one of my 'get the code working' tests. I would prefer not fill my factory with if/else if etc. as the number of "VehicleTypes" in my project is bound to grow quite large.

    @toas1: Your solution does enable the code to compile, thank you. My example was flawed.

    I am now using this setup:

    abstract class Vehicle{
      internal abstract void DoVehicleSpecificStuff();
    }  
    abstract class Car : Vehicle;  
    abstract class Plane : Vehicle; 
    
    public class VehicleFactory<T> where T : Vehicle {
       public static T CreateVehicle(){
           Vehicle result = (T)Activator.CreateInstance(typeof(T));
           result.DoVehicleSpecificStuff();
           // Do stuff generic to all Vehicles based on Vehicle Specific stuff
           return (T)result;
       }
    }


    My Car and Plane both have "Move()" functions, but the "GenerateSeats()" function of each is different. Primarily all Cars (in my world) have exactl 4 seats, never more, never less. While Planes have X seats. Not sure if this made things more clear or less clear.

    Marking you both as answered because it was helpful, but I'd love some more input on my situation/setup.

    Wednesday, June 2, 2010 3:04 PM
  • User-2004844803 posted

    My Car and Plane both have "Move()" functions, but the "GenerateSeats()" function of each is different. Primarily all Cars (in my world) have exactl 4 seats, never more, never less. While Planes have X seats. Not sure if this made things more clear or less clear.

    was this a question or just a statment Smile?


    Wednesday, June 2, 2010 3:40 PM
  • User631596016 posted

    Seems I left out a question statement, apologies.

    Is the method I'm handling things in my second post seem correct/logical? Does it follow common design patterns as you understand them? Is there some blatantly fail logic that I'm opening myself up for?

    Do I have any more questions? ;)

    Wednesday, June 2, 2010 4:29 PM
  • User-2004844803 posted

    ok, you will have an abstract method "GenarateSeats" on your vehicle class with different implementations in both Plane and Car that you will call from your factory? That seems logical to me but I can figure out if it follows any specific pattern. But sure, thats the way to do it.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, June 3, 2010 1:19 AM
  • User631596016 posted

    Thank you Toas1! Guess I just needed a little affirmation(?). Working alone limits my sounding board options.


    Thursday, June 3, 2010 11:06 AM