派生タイプを返すことができる工場をどのように作成しますか?
-
23-10-2019 - |
質問
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 }
ハートビートアラームはアラームから派生しています。コンパイルエラーを取得しています。「タイプを暗黙的に変換できません...明示的な変換が存在します(キャストがありませんか?)」。派生タイプを返すようにこれを設定するにはどうすればよいですか?
編集
答えてくれてありがとう。コンパイルエラーを10分以内に修正したため、エラー全体を投稿しませんでした。しかし、言及されたさまざまなアプローチに感謝しました。
記録のために、「型 'goalarmscs.heartbeatalarm」を暗黙的に変換することはできません。「goalarmscs.alarm」に明示的な変換が存在します(キャストがありませんか?)」。 (私は思う。)8行目でエラーが発生していた。
セス
解決
以下は、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);
}
}
他のヒント
あなたの最善の策は作ることです 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);