私はC#、. NET3.5を使用しています。イベントの利用方法、クラスでの宣言方法、他の場所からのイベントのフック方法などを理解しています。不自然な例:
public class MyList
{
private List<string> m_Strings = new List<string>();
public EventHandler<EventArgs> ElementAddedEvent;
public void Add(string value)
{
m_Strings.Add(value);
if (ElementAddedEvent != null)
ElementAddedEvent(value, EventArgs.Empty);
}
}
[TestClass]
public class TestMyList
{
private bool m_Fired = false;
[TestMethod]
public void TestEvents()
{
MyList tmp = new MyList();
tmp.ElementAddedEvent += new EventHandler<EventArgs>(Fired);
tmp.Add("test");
Assert.IsTrue(m_Fired);
}
private void Fired(object sender, EventArgs args)
{
m_Fired = true;
}
}
しかし、私がしていることnot理解しているのは、イベントハンドラーを宣言するときです
public EventHandler<EventArgs> ElementAddedEvent;
初期化されることはありません-では、正確には、ElementAddedEventとは何ですか?それは何を指しているのですか? EventHandlerが初期化されないため、以下は機能しません。
[TestClass]
public class TestMyList
{
private bool m_Fired = false;
[TestMethod]
public void TestEvents()
{
EventHandler<EventArgs> somethingHappend;
somethingHappend += new EventHandler<EventArgs>(Fired);
somethingHappend(this, EventArgs.Empty);
Assert.IsTrue(m_Fired);
}
private void Fired(object sender, EventArgs args)
{
m_Fired = true;
}
}
EventHandler.CreateDelegate(...)があることに気付きましたが、すべてのメソッドシグネチャは、これが通常のElementAddedEvent + = new EventHandler(MyMethod)を介して既存のEventHandlerにデリゲートをアタッチするためにのみ使用されることを示唆しています。
what私がやろうとしていることが役立つかどうかはわかりません...しかし、最終的には、LINQで抽象親DataContextを考え出し、その子が必要なテーブルタイプを登録できるようにします。監視された」ので、BeforeUpdateやAfterUpdateなどのイベントを設定できますが、タイプに固有です。このようなもの:
public class BaseDataContext : DataContext
{
private static Dictionary<Type, Dictionary<ChangeAction, EventHandler>> m_ObservedTypes = new Dictionary<Type, Dictionary<ChangeAction, EventHandler>>();
public static void Observe(Type type)
{
if (m_ObservedTypes.ContainsKey(type) == false)
{
m_ObservedTypes.Add(type, new Dictionary<ChangeAction, EventHandler>());
EventHandler eventHandler = EventHandler.CreateDelegate(typeof(EventHandler), null, null) as EventHandler;
m_ObservedTypes[type].Add(ChangeAction.Insert, eventHandler);
eventHandler = EventHandler.CreateDelegate(typeof(EventHandler), null, null) as EventHandler;
m_ObservedTypes[type].Add(ChangeAction.Update, eventHandler);
eventHandler = EventHandler.CreateDelegate(typeof(EventHandler), null, null) as EventHandler;
m_ObservedTypes[type].Add(ChangeAction.Delete, eventHandler);
}
}
public static Dictionary<Type, Dictionary<ChangeAction, EventHandler>> Events
{
get { return m_ObservedTypes; }
}
}
public class MyClass
{
public MyClass()
{
BaseDataContext.Events[typeof(User)][ChangeAction.Update] += new EventHandler(OnUserUpdate);
}
public void OnUserUpdated(object sender, EventArgs args)
{
// do something
}
}
これについて考えると、私はイベントの群れの下で何が起こっているのか本当に理解していないことに気づきました-そして私は理解したいと思います:)
私はこれを 記事 にかなり詳細に書いていますが、 代理人 自体にかなり満足していると仮定して、ここに要約を示します。
フィールドのようなイベントの場合、同期がありますが、それ以外の場合、追加/削除はDelegateを呼び出すだけです。 Combine / Remove 自動生成されたフィールドの値を変更します。これらの操作は両方ともバッキングフィールドに割り当てられます-デリゲートは不変であることを忘れないでください。言い換えると、自動生成されたコードは次のようになります。
// Backing field
// The underscores just make it simpler to see what's going on here.
// In the rest of your source code for this class, if you refer to
// ElementAddedEvent, you're really referring to this field.
private EventHandler<EventArgs> __ElementAddedEvent;
// Actual event
public EventHandler<EventArgs> ElementAddedEvent
{
add
{
lock(this)
{
// Equivalent to __ElementAddedEvent += value;
__ElementAddedEvent = Delegate.Combine(__ElementAddedEvent, value);
}
}
remove
{
lock(this)
{
// Equivalent to __ElementAddedEvent -= value;
__ElementAddedEvent = Delegate.Remove(__ElementAddedEvent, value);
}
}
}
この場合に生成されるフィールドの初期値はnull
-であり、すべてのサブスクライバーが削除されると、Delegate.Removeの動作であるため、常にnull
になります。
ヌルチェックを回避するために、「no-op」ハンドラーでイベントをサブスクライブする場合は、次のようにします。
public EventHandler<EventArgs> ElementAddedEvent = delegate {};
delegate {}
は、パラメータを気にせず、何もしない匿名メソッドです。
それでも不明な点がある場合は、お問い合わせください。サポートさせていただきます。