1

I currently have a factory class that looks like this:

public static class OrderFactory
{
    public static Order GetOrder(OrderInformation orderInfo, Logger logger, string overlayPath)
    {
        switch (orderInfo.Type)
        {
            case OrderType.Print:
                return new Print(orderInfo, logger, overlayPath);
            case OrderType.Cad:
                return new Cad(orderInfo, logger, overlayPath);
            case OrderType.Litho:
                return new Litho(orderInfo, logger, overlayPath);
            case OrderType.Error:
            default:
                return new OrderError(orderInfo, logger, overlayPath);
        }
    }
}

public abstract class Order
    {
        protected OrderInformation OrderInfo { get; set; }
        protected Logger Logger { get; set; }
        protected string OverlayPath { get; set; }
        public Order(OrderInformation orderInfo, Logger logger, string overlayPath)
        {
            OrderInfo = orderInfo;
            Logger = logger;
            OverlayPath = overlayPath;
        }
        public abstract Task<bool> CreateImage()
    }

public class Print : Order
    {
        public Print(OrderInformation orderInfo, Logger logger, string overlayPath)
            : base(orderInfo, logger, overlayPath)
        { }

        public override async Task<bool> CreateThumbs(CorelAppWrapper corelAppWrapper, int timeBeforeFirstAbort, int timeBeforeRetryAbort)
        {

I would like to use a delegate pattern or something else mostly to avoid using a switch statement and also knowing one day we will have to quickly extend this method. I want to use the Delegate Dictionary Pattern or something similar to it. I tried code like this:

    private delegate Order Order(OrderInformation orderInfo, Logger logger, string overlayPath);

    private static readonly Dictionary<OrderType, Order>
           mTypeConstructors = new Dictionary<OrderType, Order>
           {
               { OrderType.Print, (orderInfo, logger, overlayPath) => new Print(orderInfo, logger, overlayPath) },
               ...//etc
           };

Doing it this way throws an error saying that Print type cannot be converted to Order type. What can I do to get around this?

Ben Hoffman
  • 8,149
  • 8
  • 44
  • 71
  • 1
    Does `Print` need to be `ScreenPrint`, to match your switch statement? – Diosjenin Jun 23 '16 at 18:51
  • @Diosjenin - No, ScreenPrint should be Print. I fixed that. Good catch. – Ben Hoffman Jun 23 '16 at 19:12
  • 1
    @BenHoffman, could you please post the definitions of the `Transfer` type and of the types of the `Order`-hierarchy? – Sergey Vyacheslavovich Brunov Jun 23 '16 at 19:22
  • @SergeyBrunov I added Order and Print info. Transfer is Order. It was a name change I missed. I fixed it. Order is an abstract method and Print inherits from it. So do Cad, Litho, and Error. – Ben Hoffman Jun 23 '16 at 19:33
  • 1
    It looks like you have a naming conflict between `Order`, the abstract class, and `Order`, the delegate type. It's probably telling you that it can't convert from *class* `Print` to *function delegate* `Order`. Try renaming the delegate type `Order` to, say, `OrderConstructor`, and see if it still complains. – Diosjenin Jun 23 '16 at 20:11

1 Answers1

1

I've achived it with some changes in your code. I've moved creation of an object from constructor for simplicity (more detail)

  public static Order GetOrder(OrderInformation orderInfo, Logger logger, string overlayPath)
    {
        return mTypeConstructors[orderInfo.Type](orderInfo, logger, overlayPath);           
    }


  private static readonly Dictionary<OrderType, Func<OrderInformation, Logger, string, Order>>
  mTypeConstructors = new Dictionary<OrderType, Func<OrderInformation, Logger, string, Order>>
               {
                 { OrderType.Print, Print.Create },
                ///...

               };


   public class Print : Order
    {
        ...

        public static Print Create(OrderInformation orderInfo, Logger logger, string overlayPath)
        {
           ...
        }
Community
  • 1
  • 1
Ilya Sulimanov
  • 7,636
  • 6
  • 47
  • 68
  • The linked post isn't quite applicable here. You can't use a constructor as a delegate, true, but OP isn't doing that - he's specifying a function *implementation* that *returns the result* of a call to a constructor. For example, you can't define `delegate List MakeLst(int count);` and use it with `MakeLst one = new List(1);`, but you *can* use it with `MakeLst one = (i) => new List(1);`. The former is a constructor, the latter is a lambda which arbitrarily happens to internally create its return value from a call to a constructor. – Diosjenin Jun 23 '16 at 21:19