views:

116

answers:

3

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

A: 

Have you tried what the compiler suggests?

return (Alarm) alarm;

Edit: This is completely wrong, but I'm leaving this answer here to preserve the discussion in the comments.

R. Bemrose
That line compiles fine without the upcast.
code4life
Sorry I am just learning c#. What if I WANT to return a derived type? Won't casting to (Alarm) return a type of Alarm rather than HeartbeatAlarm?Seth
Seth Spearman
@Seth, Your return type is Alarm, the returned object is going to be Alarm with or without a cast. If you want to explicitly use a derived type, you will have to cast it to the derived type once you've received the object. Something like DerivedAlarm alarm = (DerivedAlarm)AlarmFactory.GetAlarm(AlarmTypes.DerivedAlarm);
Anthony Pegram
Okay...thanks. I get it. Bottom line is you can't do it.
Seth Spearman
@Seth: You are misunderstanding how reference conversions work. You're confusing *what the compiler knows at compile time* (this object is some kind of Animal) with *what the object is at runtime* (a Giraffe). Casting a Giraffe to Animal just tells the compiler "forget that you knew this was a Giraffe". At runtime, it's still a Giraffe.
Eric Lippert
Eric,Thanks for both your comments. And your explanation of the above. I thought it might be something like that. So even though I am casting to Animal it is still a giraffe. Which is why Giraffe = (Giraffe)AnimalFactory.GetAnimal works. Thanks. Seth. PS I love your blog.
Seth Spearman
Whoops, re-reading the question, I should have realized that the problem was in the assignment of the variable after it's returned. I would delete this answer, but that would delete the discussion along with it.
R. Bemrose
+2  A: 

Your best bet would be to make Alarm an interface, or if that's not possible, create an IAlarm interface, and inherit from this interface for both Alarm and HeartbeatAlarm.

AlarmFactory.GetAlarm should return an IAlarm instance. Likewise, HeartbeatAlarm.GetAlarm() should return an IAlarm instance.

This should eliminate any compiler errors, plus the upside is that all relationships are cleanly contractual, which should make the code that much more future-friendly.

code4life
I was under the impression that `HeartbearAlarm` and `Alarm` were Quartz types, although I've never used Quartz.
R. Bemrose
They are not quartz types...although I am using quartz in this project.
Seth Spearman
+3  A: 

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);
    }
}
Dr. Wily's Apprentice
Thanks for your incredibly thorough answer. Seth
Seth Spearman