C++/CLI からイベントを発生させる適切な方法は何だろうと思っていました。C# では、最初にハンドラーのコピーを作成し、それが null でないかどうかを確認してから、それを呼び出す必要があります。C++/CLI にも同様の方法はありますか?
3 に答える
これがすべてではありません!通常、C++/CLI の null イベント ハンドラーについて心配する必要はありません。これらのチェックのコードが生成されます。次の単純な C++/CLI クラスについて考えてみましょう。
public ref class MyClass
{
public:
event System::EventHandler ^ MyEvent;
};
このクラスをコンパイルし、Reflectorを使用して逆アセンブルすると、次の c# コードが得られます。
public class MyClass
{
// Fields
private EventHandler <backing_store>MyEvent;
// Events
public event EventHandler MyEvent
{
[MethodImpl(MethodImplOptions.Synchronized)] add
{
this.<backing_store>MyEvent = (EventHandler) Delegate.Combine(this.<backing_store>MyEvent, value);
}
[MethodImpl(MethodImplOptions.Synchronized)] remove
{
this.<backing_store>MyEvent = (EventHandler) Delegate.Remove(this.<backing_store>MyEvent, value);
}
raise
{
EventHandler <tmp> = null;
<tmp> = this.<backing_store>MyEvent;
if (<tmp> != null)
{
<tmp>(value0, value1);
}
}
}
}
raise メソッドで通常のチェックが行われています。カスタムの動作が本当に必要でない限り、上記のクラスのようにイベントを宣言し、null ハンドラーを恐れることなくイベントを発生させることができます。
C++/CLI を使用するとraise
、カスタム イベントnull
ハンドラーでオーバーライドできるため、イベントを発生させるときにテストしたりコピーしたりする必要はありません。もちろん、カスタムの中でraise
これを行う必要があります。
正確さのために MSDN から改作された例:
public delegate void f(int);
public ref struct E {
f ^ _E;
public:
void handler(int i) {
System::Console::WriteLine(i);
}
E() {
_E = nullptr;
}
event f^ Event {
void add(f ^ d) {
_E += d;
}
void remove(f ^ d) {
_E -= d;
}
void raise(int i) {
f^ tmp = _E;
if (tmp) {
tmp->Invoke(i);
}
}
}
static void Go() {
E^ pE = gcnew E;
pE->Event += gcnew f(pE, &E::handler);
pE->Event(17);
}
};
int main() {
E::Go();
}
レイズがプライベートではないという問題がある場合は、ドキュメントのように明示的に実装します。
http://msdn.microsoft.com/en-us/library/5f3csfsa.aspx
要約すれば:
eventキーワードだけを使用すると、「些細な」イベントが作成されます。コンパイラはadd / remove / raiseとデリゲート メンバーを生成します。生成されたraise関数 (ドキュメントが言うように) はnullptrをチェックします。些細なイベントはここに文書化されています:
http://msdn.microsoft.com/en-us/library/4b612y2s.aspx
たとえば、昇給をプライベートにするなど、「より多くの制御」が必要な場合は、リンクに示されているようにメンバーを明示的に実装する必要があります。デリゲート型のデータ メンバーを明示的に宣言する必要があります。次に、イベントキーワードを使用して、Microsoft の例のように、イベント関連のメンバーを宣言します。
// event keyword introduces the scope wherein I'm defining the required methods
// "f" is my delegate type
// "Event" is the unrealistic name of the event itself
event f^ Event
{
// add is public (because the event block is public)
// "_E" is the private delegate data member of type "f"
void add(f ^ d) { _E += d; }
// making remove private
private:
void remove(f ^ d) { _E -= d; }
// making raise protected
protected:
void raise(int i)
{
// check for nullptr
if (_E)
{
_E->Invoke(i);
}
}
}// end event block
冗長ですが、そこにあります。
-ライリー。