Как сделать фабрику, которая может вернуть производные типы?

StackOverflow https://stackoverflow.com/questions/2960900

Вопрос

Я создал фабричный класс под названием The 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    }

Сердиториальное сигнализация получена из тревоги. Я получаю ошибку компиляции «не может неявно преобразовать тип ... существует явное преобразование (вам не хватает актера?)». Как мне настроить это, чтобы вернуть производственный тип?

РЕДАКТИРОВАТЬ

Спасибо всем за ваши ответы. Я исправил ошибку компиляции в течение десяти минут, поэтому я не публиковал всю ошибку. Но я оценил различные подходы, которые были упомянуты.

Для записи это было «не может быть неявно преобразовать тип« oalarmscs.heartbeatalarm », чтобы« uctarmscs.alarm », явное преобразование (вам не хватает актерского состава?)». (Я думаю.) Ошибка произошла в строке 8.

Сет

Это было полезно?

Решение

Ниже приведено решение, которое включает в себя определенную функцию GetheArtBeatAlarm для извлечения объекта HeartBeatAlarm, а также общей функции 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);
    }
}

Другие советы

Лучше всего будет сделать Alarm интерфейс, или если это невозможно, создайте IAlarm интерфейс и наследуют от этого интерфейса для обоих Alarm а также HeartbeatAlarm.

AlarmFactory.GetAlarm должен вернуть IAlarm пример. Так же, HeartbeatAlarm.GetAlarm() должен вернуть IAlarm пример.

Это должно устранить любые ошибки компилятора, плюс потенциал, что все отношения являются чистыми контрактными, что должно сделать код гораздо более благоприятным для будущего.

Вы пробовали то, что предлагает компилятор?

return (Alarm) alarm;

РЕДАКТИРОВАТЬ: Это совершенно неправильно, но я оставляю этот ответ здесь, чтобы сохранить обсуждение в комментариях.

Как некоторые уже предположили, избыточный интерфейс - это простой способ сделать это. Похоже, чистый пример может помочь будущим посетителям ..

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);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top