CS801~2000

C# コンパイラ エラー CS1545:インデクサーとアクセサーの呼び出し方法について解説

CS1545エラーは、C#でプロパティやインデクサーの添字構文が直接呼び出せない場合に発生します。

エラー解消には、インデックス付きの記述ではなく、getsetアクセサーメソッドを明示的に呼び出す方法に修正してください。

CS1545エラー詳細

エラー発生状況と原因

プロパティ、インデクサー、アクセサーの仕様

C#では、プロパティは内部にgetやsetというアクセサーを持ち、クラスの状態に安全にアクセスするための仕組みとなっています。

また、インデクサーは配列のように添字を利用してオブジェクトの要素にアクセスするための特殊なメンバーです。

アクセサーはプロパティやインデクサーにおいて、値の取得や設定のために利用され、直接呼び出すことはできません。

つまり、これらのメンバーは通常のメソッド呼び出しとは異なり、添字構文やプロパティ構文を使って間接的に利用される仕組みになっています。

添字構文の誤用の具体例

C#でインデクサーを持つオブジェクトに対し、添字構文でアクセスしようとする際、内部的にはアクセサーの呼び出しが行われます。

しかし、アクセサーを直接呼び出す設計になっていない場合、こうした呼び出しが失敗し、エラーCS1545が発生します。

例えば、以下のコードは誤った使用例を示しています。

using System;
public class Employee {
    public Employee(string name, int id) {
        // コンストラクタ内で初期化
    }
    public string Name {
        get { return "従業員名"; }
    }
}
public class Manager {
    // 添字付きプロパティではなく、アクセサーメソッドとして定義された場合
    private Employee GetReport(string key) {
        // 従業員を取得するロジック(仮)
        return null;
    }
    private void SetReport(string key, Employee employee) {
        // 従業員を設定するロジック(仮)
    }
    // 通常のインデクサーとして利用できない例
}
public class Program {
    public static void Main() {
        Manager manager = new Manager();
        Employee employee = new Employee("John Doe", 100);
        // 以下の行はCS1545エラーを発生させる可能性がある
        // manager.Report[employee.Name] = employee; // 誤った呼び出し方
        Console.WriteLine("CS1545エラーの誤用例");
    }
}
CS1545エラーの誤用例

エラーメッセージの内容

表示されるエラーメッセージとその意味

コンパイラはエラー発生時に以下のようなメッセージを表示します。

「プロパティ、インデクサー、またはイベント ‘property’ は、この言語でサポートされていません。

アクセサーメソッドの ‘set accessor’ または ‘get accessor’ を直接呼び出してください。」

このメッセージは、インデクサーやプロパティに設定されたアクセサーを、通常通りの添字構文やプロパティ構文で呼び出すべきであるという設計上のルールに反していることを示しています。

直接アクセサーメソッドとして呼び出そうとすると、C#の仕様上サポートされず、このエラーが発生するのです。

インデクサーとアクセサーの仕組み

インデクサーの基本

添字構文によるアクセスの仕組み

インデクサーは、オブジェクトをまるで配列のように扱うために使用されます。

インデクサーは以下のように定義され、添字構文で値の取得や設定が行えるようになっています。

using System;
public class DataCollection {
    private string[] data = new string[10];
    // 添字を定義するインデクサー
    public string this[int index] {
        get {
            // 添字が範囲外でないかチェックすることが望ましい
            return data[index];
        }
        set {
            // データの設定
            data[index] = value;
        }
    }
}
public class Program {
    public static void Main() {
        DataCollection collection = new DataCollection();
        collection[0] = "最初のデータ";  // setアクセサーが呼ばれる
        Console.WriteLine(collection[0]); // getアクセサーが呼ばれる
    }
}
最初のデータ

上記の例では、this[int index]としてインデクサーが宣言され、collection[0]のようにアクセスすることで、内部のデータに対して安全に操作が可能となっています。

この仕組みにより、添字構文が内部的にgetやsetアクセサーを利用することが理解できます。

アクセサーの役割

getアクセサーとsetアクセサーの違い

プロパティやインデクサーにおいて、getアクセサーは値を返すために用いられ、setアクセサーは値を代入するために使用されます。

getアクセサーは読み取り専用の場合に、setアクセサーは書き込み専用あるいは読取・書込の両方を可能にする場合に定義されます。

例えば、以下のコードはgetsetの両方を持つプロパティを示しています。

using System;
public class Product {
    private int price;
    public int Price {
        get {
            // 値を返す
            return price;
        }
        set {
            // 値の検証を行いながら設定
            if(value >= 0)
                price = value;
        }
    }
}
public class Program {
    public static void Main() {
        Product product = new Product();
        product.Price = 150;              // setアクセサーで値が設定される
        Console.WriteLine(product.Price); // getアクセサーで値が取得される
    }
}
150

この例では、Priceプロパティのgetアクセサーは内部のprice変数の値を返し、setアクセサーは値を検証しながら設定します。

アクセサーの役割の使い分けは、オブジェクトの整合性を保ちながら状態を管理するために重要です。

エラー回避の修正方法

誤った実装例

添字構文による誤用パターン

先述のCS1545エラーは、インデクサーやプロパティのアクセサーを直接呼び出す誤用パターンによって発生します。

たとえば、以下の例は誤った実装例となります。

using System;
public class Employee {
    public Employee(string name, int id) {
        // 従業員の初期化
    }
    public string Name {
        get { return "従業員名"; }
    }
}
public class Manager {
    // インデクサーとして登録しようとするが、実際はアクセサーメソッドに依存している
    public Employee this[string key] {
        // 内部的にアクセサーを利用するが、実際の呼び出しはメソッド経由で行うべき
        get { return GetReport(key); }
        set { SetReport(key, value); }
    }
    private Employee GetReport(string key) {
        // 実際のデータ取得処理(仮実装)
        return null;
    }
    private void SetReport(string key, Employee employee) {
        // 実際のデータ設定処理(仮実装)
    }
}
public class Program {
    public static void Main() {
        Manager manager = new Manager();
        Employee employee = new Employee("Alice", 101);
        // 以下の行は直接アクセサーを呼び出そうとして誤った実装例となる
        // manager[employee.Name] = employee; // 添字構文の誤用によりCS1545が発生する可能性がある
        Console.WriteLine("誤った実装例(添字構文による直接呼び出し)");
    }
}
誤った実装例(添字構文による直接呼び出し)

この例では、添字構文で直接アクセサーを呼び出そうとしており、C#の仕様に反しているためエラーが発生します。

正しい実装例

明示的なget/setアクセサーメソッドの呼び出し方法

CS1545エラーを回避するためには、インデクサーを直接利用するのではなく、明示的にgetやsetアクセサーメソッドを呼び出す必要があります。

以下の例は、正しい実装方法を示しています。

using System;
public class Employee {
    public Employee(string name, int id) {
        // 従業員の初期化
    }
    public string Name {
        get { return "従業員名"; }
    }
}
public class Manager {
    // 添字構文ではなく、明示的なメソッドとしてアクセサーを定義する
    public Employee GetReport(string key) {
        // 実際のデータ取得処理(仮実装)
        return new Employee("Alice", 101);
    }
    public void SetReport(string key, Employee employee) {
        // 実際のデータ設定処理(仮実装)
        Console.WriteLine($"{key}に従業員{employee.Name}を設定しました");
    }
}
public class Program {
    public static void Main() {
        Manager manager = new Manager();
        Employee employee = new Employee("Alice", 101);
        // 正しい呼び出し方:明示的にメソッドを呼び出す
        manager.SetReport(employee.Name, employee);
        Employee retrievedEmployee = manager.GetReport(employee.Name);
        Console.WriteLine("正しい実装例(メソッド呼び出し)");
        Console.WriteLine(retrievedEmployee.Name);
    }
}
Aliceに従業員従業員名を設定しました
正しい実装例(メソッド呼び出し)
従業員名

この例では、添字構文を廃止し、GetReportSetReportという明示的なメソッドを定義して、値の取得や設定を行っています。

これにより、CS1545エラーを回避し、C#の仕様に沿った実装となっています。

まとめ

この記事では、CS1545エラーの発生状況と原因、プロパティ、インデクサー、アクセサーの仕様を理解するための基礎知識について解説しています。

添字構文の誤用によるエラーの具体例や、表示されるエラーメッセージの意味を説明し、インデクサーとアクセサーの仕組みや各アクセサーの役割についても詳しく解説しました。

また、誤った実装例と正しい実装例を示し、明示的なget/setメソッドの利用方法を確認できる内容となっています。

関連記事

Back to top button
目次へ