Search code examples
c#factoryimplicit-conversionderived-types

How do you make a Factory that can return derived types?


I have created a factory class called AlarmFactory as such...

1    class AlarmFactory
2    {
3        public static Alarm GetAlarm(AlarmTypes alarmType)  //factory ensures that correct alarm is returned and right func pointer for trigger creator.
4        {
5            switch (alarmType)
6            {
7                case AlarmTypes.Heartbeat:
8                    HeartbeatAlarm alarm = HeartbeatAlarm.GetAlarm();
9                    alarm.CreateTriggerFunction = QuartzAlarmScheduler.CreateMinutelyTrigger;
10                    return alarm;
11
12                   break;
13                default:
14                
15                    break;
16            }
17        }
18    }

Heartbeat alarm is derived from Alarm. I am getting a compile error "cannot implicitly convert type...An explicit conversion exists (are you missing a cast?)". How do I set this up to return a derived type?

EDIT

THANK YOU ALL FOR YOUR ANSWERS. I fixed the compile error within ten minutes which is why i did not post the whole error. But I appreciated the different approaches that were mentioned.

For the record it was "Cannot implicitly convert type 'goAlarmsCS.HeartbeatAlarm' to 'goAlarmsCS.Alarm' An explicit conversion exists (are you missing a cast?)". (I think.) The error was occurring on line 8.

Seth


Solution

  • Below is a solution that includes a specific GetHeartbeatAlarm function to retrieve a HeartbeatAlarm object as well as a generic GetAlarm function to return an alarm whose type is determined by the generic parameter. At the bottom there is some example code showing how this would be called:

    enum AlarmTypes
    {
        Heartbeat,
        AnotherAlarm,
        // ...
    }
    
    delegate void CreateTriggerDelegate();
    
    class Alarm
    {
        // ...
    
        public CreateTriggerDelegate CreateTriggerFunction { get; set; }
    }
    
    class HeartbeatAlarm : Alarm
    {
        // ...
    
        public static HeartbeatAlarm GetAlarm()
        {
            return new HeartbeatAlarm();
        }
    }
    
    class QuartzAlarmScheduler
    {
        public static CreateTriggerDelegate CreateMinutelyTrigger { get; set; }
    }
    
    class AlarmFactory
    {
        public static Alarm GetAlarm(AlarmTypes alarmType)  //factory ensures that correct alarm is returned and right func pointer for trigger creator.
        {
            switch (alarmType)
            {
                case AlarmTypes.Heartbeat:
                    return GetHeartbeatAlarm();
                default:
                    throw new ArgumentException("Unrecognized AlarmType: " + alarmType.ToString(), "alarmType");
            }
        }
    
        static Alarm _GetAlarm<T>()
            where T : Alarm
        {
            Type type = typeof(T);
            if (type.Equals(typeof(HeartbeatAlarm)))
                return GetHeartbeatAlarm();
            else
                throw new ArgumentException("Unrecognized generic Alarm argument: " + type.FullName, "T");
        }
    
        public static T GetAlarm<T>()
            where T : Alarm
        {
            return (T)_GetAlarm<T>();
        }
    
        public static HeartbeatAlarm GetHeartbeatAlarm()
        {
            HeartbeatAlarm alarm = HeartbeatAlarm.GetAlarm();
            alarm.CreateTriggerFunction = QuartzAlarmScheduler.CreateMinutelyTrigger;
            return alarm;
        }
    }
    
    class Example
    {
        static void GetAlarmExamples()
        {
            HeartbeatAlarm alarm;
    
            alarm = AlarmFactory.GetHeartbeatAlarm();
    
            alarm = AlarmFactory.GetAlarm<HeartbeatAlarm>();
    
            alarm = (HeartbeatAlarm)AlarmFactory.GetAlarm(AlarmTypes.Heartbeat);
        }
    }