CS801~2000

C# コンパイラ エラー CS1728:Nullable 値型のメンバーにデリゲートをバインドできない原因について解説

CS1728 エラーは、Nullable 値型のメンバーにデリゲートをバインドしようとする場合に発生します。

例えば、int?型の変数のメソッド GetValueOrDefault をデリゲートに割り当てると、型の整合性が取れずにエラーとなります。

エラー内容に沿って、対象メンバーの取り扱いやデリゲートの型を確認する必要があります。

エラーの概要

エラーコードCS1728の説明

エラーコードCS1728は、C#のコンパイラが「Nullable値型のメンバーにデリゲートをバインドできません」という旨のメッセージを表示するときに発生します。

これは、System.Nullable<T>型が持つメソッド(例えば、GetValueOrDefault)を直接デリゲートへバインドしようとすると、型システム上の制約により許容されないためです。

具体的には、Nullable値型のメンバーに対してデリゲートを割り当てるときに、正しい型の解決ができなくなった場合にこのエラーが発生します。

エラーが発生する状況

このエラーは、Nullable値型(たとえば、int?double?)で定義されるメソッドをデリゲートに直接バインドしようとする状況で発生します。

たとえば、以下のようなコードでは、int?型の変数xGetValueOrDefaultメソッドをデリゲートに代入する際にエラーになるため、コンパイルエラーCS1728が発生してしまいます。

CS1728エラーの発生原因

Nullable値型とデリゲートの関係

Nullable値型は構造体として定義されているため、通常の参照型や値型とは異なる扱いになります。

デリゲートは特定のメソッドを参照する仕組みですが、Nullable値型のメンバーに対して直接デリゲートを作成する場合、型の互換性に関する問題が生じます。

特に、Nullable型のメソッドは内部的にラップされた形で提供されるため、そのメソッドシグネチャが期待する型と一致しない場合があります。

型の整合性の制約

C#の型システムは、デリゲートのパラメータや戻り値の型が厳密に一致することを要求します。

Nullable値型のメソッドを指し示す際、コンパイラはそのメソッドが保持する値型とNullable型の間で正確な整合性を確認できないため、エラーとなります。

たとえば、GetValueOrDefaultは、内部的には値型のデフォルト値を返すメソッドですが、Nullable型自体の振る舞いとは完全には一致しません。

この違いが、デリゲートにバインドする際の整合性エラーの原因となっています。

実例によるエラー再現

コード例の解説

以下の例は、エラーCS1728が発生する状況を再現するためのサンプルコードです。

実例では、int?型の変数に対してGetValueOrDefaultメソッドをデリゲートとしてバインドしようとしています。

変数宣言とNullable型の使用

サンプルコードでは、int?型の変数xyを使用しています。

int?型は、必要に応じて値がnullになることを許容するため、例えばデータベースの値や計算結果が存在しない場合などのシナリオに用いられます。

デリゲートの定義とバインド

コード内で、ジェネリックなデリゲートが定義され、GetValueOrDefaultメソッドを直接デリゲートにバインドする試みがなされています。

この場合、Nullable型のメソッドのシグネチャがデリゲートの型と一致せず、コンパイラがエラーを報告します。

エラー発生箇所の詳細

エラーは、両方の変数xおよびyに対してGetValueOrDefaultをデリゲートに代入する行で発生します。

以下は、エラーが発生するサンプルコードの一部です。

using System;
class Test
{
    // ジェネリックデリゲートの定義
    delegate T GetT<T>();
    static void Main()
    {
        // Nullable型の変数宣言
        int? x = null;
        int? y = 5;
        // 以下の行でコンパイルエラーCS1728が発生する
        GetT<int> d1 = x.GetValueOrDefault;
        GetT<int> d2 = y.GetValueOrDefault;
    }
}
// コンパイルエラー: CS1728: 'int?' のメンバーであるため、デリゲートを 'member' にバインドできません。

上記のコードでは、変数xおよびyに対してGetValueOrDefaultメソッドを直接デリゲートにバインドしようとしているため、コンパイラからエラーが報告されます。

エラー解消のための対策

対象メンバーの正しい扱い方

対策の一つは、Nullable型のメソッドを直接デリゲートにバインドするのではなく、ラッパーメソッドやラムダ式を利用して正しく呼び出す方法です。

この方法では、Nullable値型のメソッドを一旦ラップすることで、デリゲートと必要なシグネチャの整合性を確保することができます。

たとえば、int?型の変数に対してGetValueOrDefaultを呼び出す場合、以下のようにラムダ式を使ってデリゲートを作成することが可能です。

型の調整方法

もう一つの方法は、Nullable型の変数からあらかじめ値を取り出して、非Nullableな値型に変換してからデリゲートをバインドする方法です。

この場合、変数がnullの場合に備えて、あらかじめデフォルト値を設定しておく必要があります。

こうすることで、デリゲートのシグネチャと呼び出し先のメソッドの型が一致するように調整できます。

コード例の改善案

修正後のコード解説

下記のサンプルコードは、エラーCS1728を回避するためにラムダ式を利用してGetValueOrDefaultの呼び出しをラップした例です。

今回の例では、デリゲートに直接Nullable型のメソッドをバインドするのではなく、ラムダ式を介して呼び出し、型の整合性を補っています。

using System;
class Test
{
    // ジェネリックデリゲートの定義
    delegate int GetInt();
    static void Main()
    {
        // Nullable型の変数宣言
        int? nullableNumber = null;
        // ラムダ式を利用してNullable型のメソッド呼び出しをラップ
        GetInt getDefaultValue = () => nullableNumber.GetValueOrDefault();
        // デリゲート呼び出し
        int result = getDefaultValue();
        Console.WriteLine(result);  // nullableNumberがnullの場合は0が出力される
    }
}
0

改善点の検証と注意事項

上記の例では、次の点で改善がなされています。

・Nullable型のメソッドを直接デリゲートにバインドせず、ラムダ式を用いて明示的に呼び出している

GetValueOrDefaultの結果として返される値型と、デリゲートの戻り値の型が一致している

この方法を利用することで、コンパイラの要求する型の整合性を確保し、CS1728エラーの解消につなげることが可能です。

コードのリファクタリング時には、対象メソッドのシグネチャと、デリゲートが求める型を十分に検証するよう注意してください。

まとめ

本記事では、コンパイラエラーCS1728の原因、具体的にはNullable値型のメンバーに直接デリゲートをバインドしようとした際に発生する型の整合性の問題について解説しました。

エラーが起こる理由として、Nullable型特有の挙動や内部実装との不一致がある点を示し、実例コードを用いてエラー再現の詳細も説明しています。

また、エラーを回避するための対策として、ラムダ式を用いる方法や型を事前に調整する方法を紹介し、修正コードを通じて実践的な解決策を提示しました。

関連記事

Back to top button
目次へ