你如何建立一个可以返回衍生类型的工厂?

时间:2010-06-02 19:22:27

标签: c# factory implicit-conversion derived-types

我已经创建了一个名为AlarmFactory的工厂类......

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    }

心跳警报来自警报。我收到编译错误“无法隐式转换类型...存在显式转换(你是否错过了演员?)”。如何设置它以返回派生类型?

修改

谢谢你的回答。我在十分钟内修复了编译错误,这就是我没有发布整个错误的原因。但我很欣赏所提到的不同方法。

对于记录,它是“无法将类型'goAlarmsCS.HeartbeatAlarm'隐式转换为'goAlarmsCS.Alarm'存在显式转换(您是否错过了转换?)”。 (我想。)错误发生在第8行。

赛斯

4 个答案:

答案 0 :(得分:4)

下面是一个解决方案,其中包含用于检索HeartbeatAlarm对象的特定GetHeartbeatAlarm函数以及用于返回类型由泛型参数确定的警报的通用GetAlarm函数。在底部有一些示例代码,显示了如何调用它:

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);
    }
}

答案 1 :(得分:3)

您最好的选择是使Alarm成为一个接口,或者如果不可能,则创建一个IAlarm接口,并继承Alarm和{{1}的此接口}。

HeartbeatAlarm应返回AlarmFactory.GetAlarm个实例。同样,IAlarm应返回HeartbeatAlarm.GetAlarm()个实例。

这应该消除任何编译器错误,而且好处是所有关系都是完全契约的,这应该使代码更加适合未来。

答案 2 :(得分:0)

您是否尝试过编译器建议的内容?

return (Alarm) alarm;

编辑:这是完全错误的,但我在这里留下这个答案以保留评论中的讨论。

答案 3 :(得分:0)

正如一些人已经建议的那样,冗余接口是实现这一目标的简单方法。看起来像一个干净的例子可能会帮助未来的访客..

public interface IAlarm
{
    public int bpm { get; set; }    // declared base props
}

public class Alarm : IAlarm
{
    public int bpm { get; set; }    // implemented base props
}

public class HeartbeatAlarm : Alarm
{
    public int min { get; set; }    // extended type specific props
}

public class FactoryMethods
{
    public static T AlarmFactory<T>(int bpm) where T : IAlarm, new()
    {
        // interfaces have no constructor but you can do this
        T alarm = new T() {
            bpm = bpm
        };

        return alarm;
    }
}

// C# will automagically infer the type now..
HeartbeatAlarm heartbeatAlarm = FactoryMethods.AlarmFactory<HeartbeatAlarm>(40);