C# コンパイラエラー CS0079:イベント呼び出しの誤用と正しい対処法について解説
CS0079はC#のコンパイルエラーで、イベントを直接呼び出そうとした際に発生します。
イベントは+=
や-=
の左側でのみ利用できるため、直接の呼び出しは許可されずエラーになります。
サンプルコードでは、イベントを通常のデリゲートのように呼び出そうとしたためにこのエラーが発生した例が示されています。
エラー原因と誤用例
イベントの基本
イベントとデリゲートの関係
C#では、event
はdelegate
をカプセル化するために用いられます。
delegate
はメソッドの参照を保持する型であり、イベントは複数のリスナーに対して通知を行うための仕組みです。
この関係により、特定の処理が発生した際に、登録された複数のメソッドを一斉に呼び出すことが可能となります。
イベントの定義方法と利用目的
イベントは通常、クラス外部から直接呼び出すことを防ぐためにevent
キーワードを使って定義されます。
イベントの定義は以下のようになります。
// delegateによる型定義
public delegate void MyEventHandler();
// イベントの定義
public event MyEventHandler SampleEvent;
このように定義することで、外部では+=
および-=
による購読解除操作のみが許可され、直接イベントを発火することはできません。
イベントの利用目的は、オブジェクト間の疎結合な通信を実現することにあります。
CS0079エラーの発生理由
直接呼び出しの制約
C#の言語仕様では、イベントは+=
や-=
の左側でしか利用できないため、イベント自体を直接呼び出すことはできません。
例えば、イベントPow
に対して以下のように直接呼び出すとCS0079エラーが発生します。
// エラー例
if (_e != null)
{
Pow(); // CS0079エラー: イベント 'Pow' は直接呼び出せません
}
このエラーは、イベントの発火が外部から制御されることを防ぎ、クラス内部でのみ安全にイベント発火ロジックを実装する意図があります。
add/removeアクセッサの役割
イベントに独自のadd
およびremove
アクセサを指定すると、イベント購読時と解除時に特定の処理を組み込むことが可能です。
例えば、以下のコードでは、購読時および解除時にコンソールへの出力が行われます。
public event MyEventHandler Pow
{
add
{
_e += value;
Console.WriteLine("in add accessor"); // 購読時の処理
}
remove
{
_e -= value;
Console.WriteLine("in remove accessor"); // 解除時の処理
}
}
この仕組みにより、イベントハンドラの追加や削除の際にログ出力や検証処理を行うことが可能となり、デバッグやトラブルシューティングに役立ちます。
サンプルコードの解析
誤ったイベント呼び出し例
イベント呼び出し時のCS0079発生箇所
次のサンプルコードは、イベントPow
を直接呼び出しているためCS0079エラーが発生する箇所を示しています。
using System;
public delegate void MyEventHandler();
public class Class1
{
private MyEventHandler _e;
public event MyEventHandler Pow
{
add
{
_e += value;
Console.WriteLine("in add accessor");
}
remove
{
_e -= value;
Console.WriteLine("in remove accessor");
}
}
public void Handler()
{
Console.WriteLine("イベントハンドラが呼び出されました");
}
public void Fire()
{
if (_e != null)
{
Pow(); // CS0079エラー: 直接呼び出しは許可されていません
// 正しい呼び出し例: _e();
}
}
public static void Main()
{
Class1 instance = new Class1();
instance.Pow += new MyEventHandler(instance.Handler);
// 以下、誤った呼び出しが含まれるサンプルコード
instance._e(); // これは直接呼び出しになるため注意
}
}
in add accessor
イベントハンドラが呼び出されました
上記コードでは、イベントPow
を直接呼び出した際にエラーが発生するため、実行する際はコメントで示した通り、裏で保持している_e
を呼び出す必要があります。
正しい呼び出し方法の検証
_eとPowの使い分け
イベントPow
は外部からの購読と解除専用で利用されるべきであり、イベントの発火には裏で保持している_e
を用います。
以下のコードは、イベント発火時に正しく_e
を利用する例となっています。
using System;
public delegate void MyEventHandler();
public class Class1
{
private MyEventHandler _e;
public event MyEventHandler Pow
{
add
{
_e += value;
Console.WriteLine("in add accessor");
}
remove
{
_e -= value;
Console.WriteLine("in remove accessor");
}
}
public void Handler()
{
Console.WriteLine("イベントハンドラが呼び出されました");
}
public void Fire()
{
// _eを通じてイベントを発火することで、CS0079エラーを回避します
if (_e != null)
{
_e();
}
}
public static void Main()
{
Class1 instance = new Class1();
instance.Pow += new MyEventHandler(instance.Handler);
instance.Fire();
}
}
in add accessor
イベントハンドラが呼び出されました
この例では、Pow
を直接呼び出さず、代わりに_e()
でイベントを発火することで、エラーを回避しています。
そのため、イベント発火の際には、Pow
と_e
の使い分けに注意する必要があります。
エラー解消の対処法
正しい修正手順
イベント呼び出し修正の具体例
CS0079エラーを解消するためには、イベントPow
の直接呼び出し部分を、内部のデリゲート変数_e
の呼び出しに変更します。
下記は、エラーが解消された具体例です。
using System;
public delegate void MyEventHandler();
public class Class1
{
private MyEventHandler _e;
public event MyEventHandler Pow
{
add
{
_e += value;
Console.WriteLine("in add accessor");
}
remove
{
_e -= value;
Console.WriteLine("in remove accessor");
}
}
public void Handler()
{
Console.WriteLine("イベントハンドラが呼び出されました");
}
public void Fire()
{
// イベントの発火は内部のデリゲート変数を使用して行います
if (_e != null)
{
_e();
}
}
public static void Main()
{
Class1 instance = new Class1();
instance.Pow += new MyEventHandler(instance.Handler);
instance.Fire(); // 正しい呼び出し方法
instance.Pow -= new MyEventHandler(instance.Handler);
}
}
in add accessor
イベントハンドラが呼び出されました
in remove accessor
この修正により、イベントを直接呼び出すことによるCS0079エラーが回避されます。
動作確認のポイント
エラー解消後に動作確認する際は、以下の点に注意してください。
- イベントに対して
+=
および-=
で正しくハンドラが追加・解除されているかをコンソール出力で確認する。 - イベント発火時に
_e
がnull
でないか判定し、null
の場合に例外が発生しないよう対策する。 - サンプルコード内の
Main
関数を利用して、実際の動作が意図した通りであるかを検証する。
こうした確認作業により、イベント呼び出しの修正が正しく反映されるかどうかをスムーズに確認できます。
まとめ
この記事では、C#におけるイベントとデリゲートの基礎、CS0079エラーの原因、および誤った実装例について解説しています。
イベントは外部からの直接呼び出しを避け、内部で安全にデリゲート変数を用いる設計である点に重点をおいています。
また、エラー解消のための修正方法と動作確認についても具体例を用いて説明しており、正しいイベント発火方法の理解が深まります。