CS2001~

C# コンパイラ エラー CS8355について解説:inパラメーターとOut属性の注意点

CS8355はC#のコンパイラエラーで、inパラメーターに[Out]属性を指定した際に発生します。

inパラメーターは読み取り専用として宣言されるため、ネイティブコードとの相互運用時に書き込みが必要な[Out]属性と矛盾してしまいます。

そのため、修正が必要となります。

CS8355 エラーの背景

エラー発生の状況

CS8355 エラーは、C# のパラメーターに対して in キーワードを使用しながら、同時に [Out] 属性を指定した場合に発生します。

これは、読み取り専用であるはずのパラメーターに対して、マーシャリング時に書き込み可能なデータとして扱おうとするため発生する矛盾が原因です。

特に、相互運用(interop)でネイティブコードと連携する際に、[Out] 属性を使って出力用のデータを受け取ろうとする場合に注意が必要です。

エラーメッセージの詳細

コンパイラは「in パラメーターに Out 属性を指定することはできません」というエラーメッセージを出力します。

これは、in パラメーターが読み取り専用であることを保証する一方で、[Out] 属性はマーシャリングの際にそのパラメーターへ書き込みを行う意図があるため、両者は設計上の目的が一致しないことを明示しています。

数式で表現すると、

in (読み取り専用)[Out] (書き込み対象)

という矛盾が生じていると言えます。

inパラメーターの基本解説

inパラメーターの特徴

in パラメーターは、値を呼び出し元から受け取る際に読み取り専用として動作する機能です。

特に大きな構造体など、コピーコストがかかるデータを渡すときに利用されることが多く、効率的にデータを扱うための仕組みとして設計されています。

呼び出し先でデータが変更されることがないため、安全性が保たれるメリットがあります。

読み取り専用としての役割

in パラメーターは、関数内で値が変更されないことをコンパイラに伝える役割を担っています。

これにより、開発者は誤ってパラメーターの値を変更してしまうリスクを抑制でき、コードの可読性と保守性が向上します。

特に多くのデータを扱う場合、不要なコピーを避けるためにも有用な機能です。

[Out]属性の基本解説

[Out]属性の目的

[Out] 属性は、主に相互運用の際に使用され、ネイティブコード側から値を書き込んでもらうために利用されます。

マーシャリングの過程で、出力専用のデータ領域を確保する指示として機能します。

そのため、呼び出し先で値が変更されることを意図している場合に適用されます。

ネイティブコードとの連携について

ネイティブコードとの連携を行う場合、C# 側のパラメーターに [Out] 属性を付与することで、マーシャラが適切なメモリ領域を割り当てる指示が渡されます。

これにより、C# とネイティブコード間でのデータの受け渡しが円滑に行われる仕組みとなっています。

しかし、in パラメーターと組み合わせると、読み取り専用と出力用という相反する属性になってしまい、エラーが発生する原因となります。

inパラメーターと[Out]属性の組み合わせで発生する問題

エラー発生の原因

in パラメーターは読み取り専用であることを保証するため、コンパイラはそのパラメーターが変更されることを未然に防ぎます。

一方、[Out] 属性はマーシャリング時にパラメーターへ値を書き戻す指示を行うため、両者の目的が衝突してしまいます。

この矛盾が原因で、C# コンパイラは CS8355 エラーを出力します。

問題となるコード例

問題箇所の特定

下記の例では、[Out] 属性を in パラメーターに指定している部分が問題となります。

宣言部分を確認することで、どのコードがエラーを誘発するか判断が可能です。

エラーメッセージの内容

具体的には、コンパイラは以下のようなエラーメッセージを出力します。

「in パラメーターに Out 属性を指定することはできません」

このメッセージは、パラメーターの設計上の矛盾を明確に示しています。

以下は、エラーを発生させる問題のあるコード例です。

using System;
using System.Runtime.InteropServices;
class Program
{
    // エラーになるサンプルコード
    public static void Example([Out] in int value)
    {
        // このメソッドは本来読み取り専用の値を受け取るはずですが、
        // [Out] 属性があるためにコンパイラエラーが発生します。
    }
    static void Main()
    {
        int number = 100;
        Example(in number);
        Console.WriteLine("プログラム終了");
    }
}
// コンパイル時に以下のエラーメッセージが出力されます。
// error CS8355: in パラメーターに Out 属性を指定することはできません

エラー修正の方法

修正前のコード例の解説

上記のコード例では、Exampleメソッドのパラメーターが [Out] in int value と定義されており、in の読み取り専用の特性と [Out] の書き込みを期待する特性が同時に指定されています。

結果として、コンパイラはその矛盾により CS8355 エラーを発生させます。

修正後の対応例と変更点

修正内容の詳細説明

修正方法としては、[Out] 属性を削除するか、in キーワードを取り除く方法があります。

  • もし、値を読み取り専用で受け取り、ネイティブコードとのマーシャリングが不要であれば、[Out] 属性を削除します。
  • 逆に、書き込みされる可能性がある場合は、in キーワードを取り除いて適切な修飾子を付ける必要があります。

以下は、[Out] 属性を削除した修正版の例です。

using System;
using System.Runtime.InteropServices;
class Program
{
    // [Out] 属性を削除して、読み取り専用の in パラメーターとして使用
    public static void Example(in int value)
    {
        // メソッド内では value の変更はできません。
        Console.WriteLine($"Example メソッド呼び出し:{value}");
    }
    static void Main()
    {
        int number = 100;
        Example(in number);
        Console.WriteLine("プログラム終了");
    }
}
Example メソッド呼び出し:100
プログラム終了

動作確認のポイント

修正後は、以下の点に注意してください。

• コンパイルエラーが解消されること

Exampleメソッド内で、in パラメーターとして渡された値が正しく表示されること

• マーシャリングを必要とする相互運用のシナリオであれば、適切な修正を行い、修正によって意図しない副作用が発生しないこと

以上のポイントを確認することで、修正前後の動作の違いが明確に把握できます。

まとめ

本記事では、C# の CS8355 エラーの原因と背景について解説しています。

in パラメーターは読み取り専用であるのに対し、[Out] 属性はマーシャリング時に値の書き込みを許容するため、両者を同時に指定すると矛盾が生じることをご理解いただけます。

これにより、問題箇所の特定や修正方法、動作確認のポイントを具体的なサンプルコードを交えて学ぶことができます。

関連記事

Back to top button
目次へ