2010-06-02 1 views
0

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

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

EDIT

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

Для записи это было «Невозможно неявно преобразовать тип« goAlarmsCS.HeartbeatAlarm »в« goAlarmsCS.Alarm »Явное преобразование существует (вам не хватает роли?)». (Я думаю.) Ошибка происходила по линии 8.

Сет

+0

Пожалуйста, разместите всю ошибку компилятора + сообщите нам, на какой строке вы ее получите. –

+3

Если HeartbeatAlarm действительно получен из Alarm, вы сможете вернуть его без ошибок. Возможно, нам понадобится больше узнать о вашем коде и более подробной информации об ошибке компилятора, включая строку, чтобы помочь. – GBegen

+0

Что возвращает HeartbeatAlarm.GetAlarm(): тип сигнала тревоги или тип HeartbeatAlarm? Я предполагаю, что это то, где возникает ошибка времени компиляции (подавление от Alarm -> HeartbeatAlarm, конечно) – code4life

ответ

4

Ниже приведено решение, которое включает определенную функцию 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); 
    } 
} 
+0

Спасибо за ваш невероятно тщательный ответ. Сет –

0

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

return (Alarm) alarm; 

Редактировать: Это совершенно неправильно, но я оставляю этот ответ здесь, чтобы сохранить обсуждение в комментариях.

+0

Эта линия компилируется без обновления. – code4life

+0

Извините, я просто изучаю C#. Что делать, если я хочу вернуть производный тип? Не будет ли кастинг (Тревога) возвращать тип Тревоги, а не HeartbeatAlarm? Seth –

+0

@Seth, ваш тип возврата - это Тревога, возвращаемый объект будет Тревога с или без приведения. Если вы хотите явно использовать производный тип, вам нужно будет передать его производному типу после получения объекта. Что-то вроде DerivedAlarm alarm = (DerivedAlarm) AlarmFactory.GetAlarm (AlarmTypes.DerivedAlarm); –

3

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

AlarmFactory.GetAlarm должен вернуть экземпляр IAlarm. Аналогично, HeartbeatAlarm.GetAlarm() должен вернуть экземпляр IAlarm.

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

+0

У меня создалось впечатление, что «HeartbearAlarm» и «Alarm» были типами кварца, хотя я никогда не использовал Quartz. – Powerlord

+0

Они не являются кварцевыми типами ... хотя я использую кварц в этом проекте. –

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); 
Смежные вопросы