多くのイベントを含むサードパーティライブラリを使用しなければならない状況にあり、非常にうまく書かれていません。それは私のコードで処理する必要があるイベントを起動しますが、私はアダプタを必要とするので、私はそれを抽象化しようとしています。問題は、イベントの一部がref
のパラメータをとる代理人型であることです。ここでは、サードパーティのライブラリがどのように見えるかの例です:私は、パラメータのリストを取って定期的にイベントを抽象化していますどのように表示するにはrefパラメータを含むC#イベントの適用
delegate void AdapteeEventHandler1(SpecificAdaptee sender, int a, int b);
delegate void AdapteeEventHandler2(SpecificAdaptee sender, ref int a); // problematic delegate
class SpecificAdaptee
{
public event AdapteeEventHandler1 Event1;
public event AdapteeEventHandler2 Event2; // problematic event
/// <summary>Exercise Event1</summary>
public void FireEvent1()
{
Event1?.Invoke(this, 1, 2);
}
/// <summary>Exercise Event2</summary>
public void FireEvent2()
{
int a = 42;
Event2?.Invoke(this, ref a);
}
}
、それはタイプAdapteeEventHandler1
のEvent1
が含まれています。問題のタイプがAdapteeEventHandler2
ですが、私は、全体のことを適応についてつもりですか最初にお見せしましょう:
#region AdaptedEventArgs
class AdaptedEventArgs1 : EventArgs
{
public int A { get; set; }
public int B { get; set; }
}
class AdaptedEventArgs2 : EventArgs
{
public int A { get; set; }
}
#endregion
/// <summary>These represent an abstraction layer between SpecificAdaptee and our own code</summary>
class Adaptor
{
private readonly SpecificAdaptee _specificAdaptee;
/// <summary>Maintains relationship between the event triggered by SpecificAdaptee and the adapted event.</summary>
private readonly IAdaptedEventHandlerManager _adaptedEventHandlerManager;
public Adaptor(SpecificAdaptee specificAdaptee, IAdaptedEventHandlerManager adaptedEventHandlerManager)
{
_specificAdaptee = specificAdaptee;
_adaptedEventHandlerManager = adaptedEventHandlerManager;
}
#region Events
/// <summary>Adapts SpecificAdaptee.Event1</summary>
public event EventHandler<AdaptedEventArgs1> AdaptedEvent1
{
add
{
_specificAdaptee.Event1 += _adaptedEventHandlerManager.RegisterEventHandler<AdapteeEventHandler1>(value,
(sender, a, b) => value.Invoke(this, new AdaptedEventArgs1 { A = a, B = b }));
}
remove
{
_specificAdaptee.Event1 -= _adaptedEventHandlerManager.UnregisterEventHandler<AdapteeEventHandler1>(value);
}
}
/// <summary>Adapts SpecificAdaptee.Event2</summary>
public event EventHandler<AdaptedEventArgs2> AdaptedEvent2
{
add
{
/* !!! ERROR HERE !!! */
_specificAdaptee.Event2 += _adaptedEventHandlerManager.RegisterEventHandler<AdapteeEventHandler2>(value,
(sender, a) => value.Invoke(this, new AdaptedEventArgs2 { A = a }));
}
remove
{
_specificAdaptee.Event2 -= _adaptedEventHandlerManager.UnregisterEventHandler<AdapteeEventHandler2>(value);
}
}
#endregion
}
だから何がここで起こっていることは、私がAdaptor.AdaptedEvent1
にイベントハンドラを登録するとき、私はAdapteeEventHandler1
でEventHandler<AdaptedEventArgs1>
を包んだということで、 SpecificAdaptee.Event1
に登録し、またAdaptedEventArgs1
をAdapteeEventHandler1
が必要とするパラメータのリストに変換します。このようにして、ユーザはのイベントに登録することができ、SpecificAdaptee
がそれ自身のイベントを発生させると解雇されます。次に、私はこれを実行するプログラムを投稿しますが、問題はAdaptedEvent2
にあることに注意してください。私は同様の方法でやりたいのですが、ref
パラメータを処理する方法がわかりません(構文エラーがあります。AdaptedEvent2
のadd
アクセサ ここでは、プロジェクトを行使コンソールアプリケーションです:
class Program
{
public static void Main(string[] args)
{
var specific = new SpecificAdaptee();
var adapter = new Adaptor(specific, new AdaptedEventHandlerManager());
adapter.AdaptedEvent1 += OnAdaptedEvent1;
adapter.AdaptedEvent2 += OnAdaptedEvent2;
specific.FireEvent1();
specific.FireEvent2();
Console.ReadLine();
}
private static void OnAdaptedEvent1(object sender, AdaptedEventArgs1 args)
{
Console.WriteLine($"{nameof(OnAdaptedEvent1)}({sender}, {args.A}, {args.B})");
}
private static void OnAdaptedEvent2(object sender, AdaptedEventArgs2 args)
{
Console.WriteLine($"{nameof(OnAdaptedEvent2)}({sender}, {args.A})");
}
}
だから、私は自分のコードを持っている私のAdaptor
のイベントに登録し、動作するようになっています方法ですと、イベントが時に解雇します。サードパーティのライブラリ(SpecificAdaptee
)は、独自のイベントを発生させます(この例では、specific.FireEvent1()
と2を呼び出してトリガーされます)。
は、私がSpecificAdaptee
のハンドラにイベントハンドラを適応マップAdaptedEventHandlerManager
するためのコードを含むので、私は通常どうなるように私には、登録し、複数のイベントハンドラの登録を解除することができます
interface IAdaptedEventHandlerManager
{
TSpecificEventHandler RegisterEventHandler<TSpecificEventHandler>(object adaptedEventHandler,
TSpecificEventHandler specificEventHandler);
TSpecificEventHandler UnregisterEventHandler<TSpecificEventHandler>(object adaptedEventHandler)
where TSpecificEventHandler : class;
}
class AdaptedEventHandlerManager : IAdaptedEventHandlerManager
{
/// <summary>
/// Remembers relation between the specific handler and general handler. Important when unsubscribing from
/// events. Key is the general event handler we are registering to events of this class. Value are specific
/// event handlers.
/// </summary>
private readonly Dictionary<object, List<object>> _eventHandlers =
new Dictionary<object, List<object>>();
public TSpecificEventHandler RegisterEventHandler<TSpecificEventHandler>(object adaptedEventHandler,
TSpecificEventHandler specificEventHandler)
{
List<object> eventHandlerList;
if (!_eventHandlers.TryGetValue(adaptedEventHandler, out eventHandlerList))
{
eventHandlerList = new List<object> { specificEventHandler };
_eventHandlers.Add(adaptedEventHandler, eventHandlerList);
}
else
{
eventHandlerList.Add(specificEventHandler);
}
return specificEventHandler;
}
public TSpecificEventHandler UnregisterEventHandler<TSpecificEventHandler>(object adaptedEventHandler)
where TSpecificEventHandler : class
{
List<object> eventHandlerList;
if (!_eventHandlers.TryGetValue(adaptedEventHandler, out eventHandlerList))
{
return null;
}
var eventHandler = eventHandlerList.FirstOrDefault();
if (eventHandler != null)
{
eventHandlerList.Remove(eventHandler);
}
if (!eventHandlerList.Any())
{
_eventHandlers.Remove(adaptedEventHandler);
}
return eventHandler as TSpecificEventHandler;
}
}
これは、基本的に、適合イベントハンドラとSpecificAdaptee
のハンドラのリストを辞書に記憶しています。 ref
パラメータを取るカスタムdelegate
タイプに退避させることなく、ref
パラメータを取ってイベントを適応させる方法があるので、私は、カスタムEventArgs
子孫で標準EventHandler<>
クラスを使用することができます。
だから私の質問は
?私はそれがかなりのコードであることを認識していますので、何かが明確でない場合は教えてください。前もって感謝します。
デバッグヘルプ(「なぜこのコードは機能していませんか?」)には、目的の動作、特定の問題またはエラー、および質問自体に再現するのに必要な最短コードが含まれている必要があります。明確な問題文がない質問は、他の読者にとって有用ではありません。参照:最小、完全、および検証可能な例を作成する方法。あなたのコメントのために – mybirthname
@mybirthnameに感謝します。これは、実際には、目的の動作(AdaptedEvent1)と問題(AdaptedEvent2)の両方を表す、最短のコードです:(ポストの最後の特定の問題を強調しようとしました。 – Caleb9
あなたは 'a'を操作する必要がありますか? – toadflakz