私はC#でカードゲームプロジェクトに取り組んでいます。このゲームでは、テーブル上のカードがサブスクライブする必要がある多くのイベントが発生します。ただし、現在アクティブになっていないカードが発生したイベントに応答しないように、イベントを動的にサブスクライブおよびサブスクライブ解除するカードが必要です。
これに対する私の解決策は、イベントごとに1つの子を持つEventManager親クラスを使用することです。これらの各マネージャーには、EventHandlerをパラメーターとして受け取るサブスクライブ/アンサブスクライブメソッドがあります。呼び出されると、メソッドは、提供されたハンドラーをそのマネージャーに割り当てられたイベントからサブスクライブ/サブスクライブ解除します。
以下のコードは、私のカードゲームと同じデザインパターンを使用し、同じ問題を抱えている基本的なコンソールアプリケーションです。Visual Studioに直接貼り付けると、実行されます。
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var example = new ExampleCard();
example.Subscribe();
example.Events.FireEventOne(null, new EventArgs());
example.UnSubscribe();
example.Events.FireEventOne(null, new EventArgs());
Console.ReadLine();
}
}
public class EventContainer
{
public delegate void EventOne(Object sender, EventArgs r);
public event EventOne OnEventOne;
public EventContainer()
{
OnEventOne += Default_Handler;
}
public void Default_Handler(object sender, EventArgs e)
{
}
public void FireEventOne(object sender, EventArgs e)
{
OnEventOne(sender, e);
}
}
public class EventManager
{
protected EventContainer Events;
public EventManager(EventContainer events)
{
Events = events;
}
public virtual void Subscribe(EventHandler handler)
{
}
public virtual void Unsubscribe(EventHandler handler)
{
}
}
public class EventOneManager : EventManager
{
public EventOneManager(EventContainer events)
: base(events)
{
}
public override void Subscribe(EventHandler handler)
{
Events.OnEventOne += new EventContainer.EventOne(handler);
}
public override void Unsubscribe(EventHandler handler)
{
Events.OnEventOne -= new EventContainer.EventOne(handler);
}
}
public class ExampleCard
{
public EventContainer Events = new EventContainer();
private readonly List<EventManager> _subscribedEvents = new List<EventManager>();
public ExampleCard()
{
_subscribedEvents.Add(new EventOneManager(Events));
}
public void Example_OnEventOneFired(object sender, EventArgs e)
{
Console.WriteLine("Event One was fired.");
}
public void Subscribe()
{
_subscribedEvents[0].Subscribe(Example_OnEventOneFired);
}
public void UnSubscribe()
{
_subscribedEvents[0].Unsubscribe(Example_OnEventOneFired);
}
}
}
EventOneManager.Subscribe()は機能しているようですが、EventOneManager.Unsubscribe()は機能しません。そのメソッドを呼び出した後、サンプルカードはイベントにサブスクライブされたままであり、その理由や修正方法がわかりません。
私が試した1つのことは、「新しいEventContainer.EventOne」呼び出しを削除して、次のようにすることでした。
public override void Unsubscribe(EventHandler handler)
{
Events.OnEventOne -= handler;
}
しかし、このエラーが発生します。タイプ'System.EventHandler'を'ConsoleApplication1.EventContainer.EventOne"に暗黙的に変換できません。何か提案はありますか?
また、カスタムEventArgsクラスを使用できるようにしたいのですが、使用しているイベントのいずれかで機能する汎用ハンドラーを渡す方法がわかりません。これは回避できますが、カスタムEventArgsを使用したいと思います。