CS0~400

C#コンパイラエラー CS0065 について解説:イベントアクセサーの正しい実装方法

CS0065エラーは、C#でイベントを定義する際に、必ずaddアクセサーとremoveアクセサーの両方を実装する必要があることを示しています。

イベントプロパティでこれらのアクセサーの一方または両方が実装されていない場合に発生するため、エラー解消には両アクセサーの実装を追加してください。

CS0065エラー発生の背景

イベントプロパティの基本仕様

C#では、イベントはデリゲートのラッパーとして実装され、クラス外から発行や解除を行うことができます。

通常、イベントはフィールドとして宣言されると、コンパイラが自動でaddアクセサーとremoveアクセサーを生成します。

しかし、イベントプロパティとして実装する場合は、両方のアクセサーを明示的に定義する必要があります。

イベントプロパティを使用する際は、以下の点に注意します。

  • インスタンスの外部からイベントに委譲先を追加・削除するための仕組みを提供
  • イベントのカプセル化を実現し、内部ロジックをコントロール可能にする

addアクセサーとremoveアクセサーの役割

addアクセサーは、イベントに委譲先(ハンドラー)を追加するために呼ばれるメソッドです。

一方、removeアクセサーは追加された委譲先を解除するために使用されます。

実装例として、以下のようにaddremoveで内部リストにイベントハンドラーを管理する仕組みを設けることが考えられます。

  • addアクセサー:新たなハンドラーをリストに追加
  • removeアクセサー:既存のハンドラーをリストから削除

フィールドと非フィールドのイベントの違い

フィールド形式のイベントでは、コンパイラがaddおよびremoveの実装を自動的に生成します。

そのため、ユーザはイベントの追加や削除のロジックを明示的に記述する必要がありません。

しかし、非フィールド形式、すなわちイベントプロパティとして実装する場合、必ず両方のアクセサーを実装しなければなりません。

その理由は以下の通りです。

  • フィールド:シンプルなイベント操作を自動管理
  • 非フィールド:イベントの発行タイミングやロジックをカスタマイズ可能な代わりに、両方のアクセサーが必要

エラーの具体例と原因分析

コンパイラエラーメッセージの解説

エラー CS0065は、イベントプロパティを定義する際にaddアクセサーとremoveアクセサーの両方が実装されていない場合に発生します。

メッセージは以下のように表示されます。

'event': イベント プロパティには、add および remove アクセサーの両方を指定する必要があります

このエラーは、開発者がイベントプロパティの実装を途中で終わらせた場合や、どちらか一方を省略した場合に発生します。

問題のあるコード例

イベントプロパティを宣言したものの、addremoveアクセサーの実装が欠如している例が以下のコードです。

アクセサー実装の欠如によるエラー発生

// CS0065_ErrorExample.cs
using System;
// カスタムイベントハンドラーのデリゲートを定義
public delegate void EventHandler(object sender, int e);
public class MyClass
{
    // イベントプロパティの宣言(アクセサー未実装)
    public event EventHandler Click // CS0065エラーが発生する部分
    {
        // addとremoveアクセサーの実装がコメントアウトされた状態
        /*
        add
        {
            // ハンドラーの追加処理(実装例では省略)
        }
        remove
        {
            // ハンドラーの削除処理(実装例では省略)
        }
        */
    }
    public static void Main()
    {
        // エントリポイント(コンパイルはこの部分で発生するエラーに気づく)
    }
}

このコードでは、Clickイベントのaddremoveアクセサーが実装されていないため、コンパイラがエラーを出力します。

正しい実装方法の解説

addアクセサーの実装例

addアクセサーでは、イベントハンドラーを内部のデリゲート変数に追加する処理を実装します。

以下のサンプルコードでは、内部に_clickHandlersという変数を用いてイベントハンドラーの管理を行っています。

using System;
// カスタムイベントハンドラーのデリゲートを定義(日本語コメント付き)
public delegate void EventHandler(object sender, int e);
public class MyClass
{
    // 内部でイベントハンドラーを保持する変数
    private EventHandler _clickHandlers;
    // イベントプロパティの実装(addアクセサー)
    public event EventHandler Click
    {
        add
        {
            // 新たなハンドラーを_internalハンドラーに追加
            _clickHandlers += value;
            // 簡単な出力で処理を確認可能
            System.Console.WriteLine("ハンドラーが追加されました");
        }
        remove
        {
            // 後の解説にて詳細説明
            _clickHandlers -= value;
            System.Console.WriteLine("ハンドラーが削除されました");
        }
    }
    public static void Main()
    {
        MyClass instance = new MyClass();
        // 匿名メソッドを使ってイベントハンドラーを追加
        instance.Click += (sender, e) =>
        {
            System.Console.WriteLine("イベントが発生しました");
        };
        // 下記はイベントを発火させるための模擬処理
        instance.TriggerClick();
    }
    // 内部用にイベント発火用のメソッドを実装
    public void TriggerClick()
    {
        _clickHandlers?.Invoke(this, 100); // 仮のパラメータ100を渡す
    }
}
ハンドラーが追加されました
イベントが発生しました

removeアクセサーの実装例

removeアクセサーは、イベントハンドラーが正しく解除されるよう実装します。

上記サンプルコード内ですでに、removeアクセサーは内包する変数から対象のハンドラーを削除する形で実装しています。

以下はその抜粋です。

remove
{
    // ハンドラーを削除して、内部変数を更新
    _clickHandlers -= value;
    System.Console.WriteLine("ハンドラーが削除されました");
}

正しいコード例の詳細解説

正しい実装では、イベントプロパティに対してaddremoveの両方で適切な処理が記述されています。

以下のポイントに注意してください。

  • 内部変数(ここでは_clickHandlers)を用いて、複数のハンドラーの追加と削除がシームレスに処理可能
  • addアクセサーでは、追加処理後にデバッグ用の出力を行い、処理の流れを確認できる
  • removeアクセサーでは、解除処理後に出力でその動作を確認
  • Main関数をエントリーポイントとして、実際にイベントの追加と発火の挙動をテストしている

この正しいコード例では、イベントが正常に発火し、ハンドラーの追加および削除が期待通りに動作することが確認できます。

イベントプロパティを使って、柔軟なイベント管理の仕組みを実装するための基本が理解できる内容となっています。

修正後の確認手順

コンパイル確認の方法

修正後は、コード全体がコンパイルエラーを出さずにビルドできるか確認する必要があります。

  • 開発環境でソリューションをビルドし、エラーが解消されたことを確認してください。
  • コンパイラからの警告やエラーメッセージが出ない場合、正しい実装が行われたと考えられます。

動作検証のポイント

コンパイルが通った後は、実際にイベントの動作を確認します。

以下のポイントに注目してください。

  • ハンドラー追加時に、addアクセサー内の出力がコンソールに表示されること
  • イベント発火後に、追加されたハンドラーが呼び出され、対応する出力が確認できること
  • removeアクセサーを利用してハンドラーを解除し、その後イベントを発火した際に、解除されたハンドラーからの出力が発生しないこと

上記の動作検証を行うことで、イベントプロパティが意図した通りに動作していることを確認することができます。

まとめ

この記事では、イベントプロパティにおけるエラー CS0065 の原因と解決方法が理解できます。

イベントプロパティを利用する際、コンパイラが自動生成するフィールドイベントと異なり、明示的にaddおよびremoveアクセサーを実装する必要がある点を解説しました。

具体例を通じて不備のあるコードと修正後の正しい実装方法、さらにはコンパイルおよび動作検証の手順について説明しており、イベントの管理方法が身につく内容です。

関連記事

Back to top button
目次へ