bugfix> c# > 投稿

おそらく、読み取り専用の構造体の概念を誤解しているかもしれませんが、このコードはコンパイルすべきではないと思います。

public readonly struct TwoPoints
{
    private readonly Point one;
    private readonly Point two;
    void Foo()
    {
        // compiler error:  Error CS1648  Members of readonly field 'TwoPoints.one'
        // cannot be modified (except in a constructor or a variable initializer)
        one.X = 5;
        //no compiler error! (and one is not changed)
        one.Offset(5, 5);
    }
 }

(C#7.3を使用しています。) 何か不足していますか?

回答 2 件
  • コンパイラが Offset を把握する方法はありません  メソッドは Point を変更します  構造体メンバー。ただし、 readonly  structフィールドは、非読み取り専用フィールドと比較して異なる方法で処理されます。この(読み取り専用ではない)構造を考えてください:

    public struct TwoPoints {
        private readonly Point one;
        private Point two;
        public void Foo() {
            one.Offset(5, 5); 
            Console.WriteLine(one.X); // 0
            two.Offset(5, 5);
            Console.WriteLine(two.X); // 5
        }
    }
    
    

    one  フィールドは読み取り専用ですが、 two  ではありません。さて、 readonly でメソッドを呼び出すと  構造体フィールド-aコピー 構造体の this としてそのメソッドに渡されます 。メソッドが構造体メンバーを変更する場合-このコピーよりもメンバーが変更されます。このため、 one への変更は見られません。  メソッドが呼び出された後-変更されていませんが、コピーが変更されています。

    two  フィールドは読み取り専用ではなく、構造体自体(コピーではなく)が Offset に渡されます  メソッド、メソッドがメンバーを変更する場合-メソッド呼び出し後にメンバーが変更されるのを確認できます。

    だから、これはあなたの readonly struct の不変性の契約を破ることができないので許可されています 。 readonly struct のすべてのフィールド   readonly である必要があります 、読み取り専用のstructフィールドで呼び出されるメソッドはそれを変更できず、コピーのみを変更できます。

    この「公式ソース」に興味がある場合-仕様(7.6.4メンバーアクセス)は次のように述べています。

    If T is a struct-type and I identifies an instance field of that struct-type:

    • If E is a value, or if the field is readonly and the reference occurs outside an instance constructor of the struct in which the field is declared, then the result is a value, namely the value of the field I in the struct instance given by E.

    • Otherwise, the result is a variable, namely the field I in the struct instance given by E.

    T  ここにターゲットタイプがあり、 I  アクセスされているメンバーです。

    最初の部分は、コンストラクタの外で、構造体のインスタンス読み取り専用フィールドにアクセスすると、結果は。 2番目の場合、インスタンスフィールドが読み取り専用ではない-結果は変数

    次に、「7.5.5関数メンバーの呼び出し」セクションで( E  ここにインスタンス式があるので、たとえば one  および two  上記):

    • If M is an instance function member declared in a value-type:

    If E is not classified as a variable, then a temporary local variable of E’s type is created and the value of E is assigned to that variable. E is then reclassified as a reference to that temporary local variable. The temporary variable is accessible as this within M, but not in any other way. Thus, only when E is a true variable is it possible for the caller to observe the changes that M makes to this.

    上で見たように、読み取り専用の構造体フィールドアクセスは value になります 、変数ではないため、 E  変数として分類されていません。

  • Evkからの回答をサポートするために、 Point's method: に関する記事があります  Point.Offset()

    Note that calling the Offset method will only have an effect if you can change the X and Y properties directly.Because Point is a value type, if you reference a Point object by using a property or indexer, you get a copy of the object, not a reference to the object. If you attempt to change X or Y on a property or indexer reference, a compiler error occurs. Similarly, calling Offset on the property or indexer will not change the underlying object. If you want to change the value of a Point that is referenced as a property or indexer, create a new Point, modify its fields, and then assign the Point back to the property or indexer.


    定義により、 Point   struct として宣言されています :ポイント

    最後になりましたが、Microsoftのブログには readonly fields についての記事があります。 、実際には struct です 、それらのパブリックプロパティも読み取り専用です。

    A read-only struct is a struct whose public members areread-only, as well as the “this” parameter.

あなたの答え