7

私はこの答えを読みました:https ://stackoverflow.com/a/9928643/16241

しかし、なぜ私の方法が不純であるのか理解できないので、私は明らかにそれを理解していません。(問題の方法はですToExactLocation())。

public struct ScreenLocation
{
    public ScreenLocation(int x, int y):this()
    {
        X = x;
        Y = y;
    }

    public int X { get; set; }
    public int Y { get; set; }

    public ExactLocation ToExactLocation()
    {
        return new ExactLocation {X = this.X, Y = this.Y};
    }

    // Other stuff
}

必要な場合は、正確な場所の構造体をここに示します。

public struct ExactLocation
{
    public double X { get; set; }
    public double Y { get; set; }

    // Various Operator Overloads, but no constructor
}

そして、これは私がそれを呼ぶ方法です:

someScreenLocation = MethodThatGivesAScreenLocation();
if (DestinationLocation == someScreenLocation.ToExactLocation())
{
     // Do stuff
}

私がそうするとき、ReSharperはそれにフラグを立てます"Impure Method is called for readonly field of value type."

なんでそんなこと言ってるの?そして、それをなくすために私は何ができますか?

4

6 に答える 6

9

入力のみに依存する値を返さないため、純粋ではありません。Xまたはの値がY変化すると、の戻り値も変化しますToExactLocation。つまり、その出力は内部の可変状態に依存します。

さらに、XまたはYのセッターが入力を変更ExactLocation する場合があります。のゲッターScreenLocationも同様です。

someScreenLocationは読み取り専用フィールドであり、値型です。ToExactLocation値、つまり読み取り専用フィールドを呼び出しています。reaodnly値型にアクセスすると、値自体の変更を回避するためにコピーが作成されます。ただし、呼び出しによってその値が変更される場合があります。これは、コピーを変更するため、多くの場合、必要な値ではありません。これが警告が表示される理由です。

この場合、無視できますが、一般的に可変値型は避けます。

編集:

単純化してみましょう...

struct Point
{
    int X;
    int Y;
    bool Mutate() { X++; Y++; }
}

class Foo
{
    public readonly Point P;
    Foo() 
    { 
        P = new Point();
        P.Mutate();  // impure function on readonly value type
    }
}

Mutate()呼び出されると、のコピーPが作成され、メソッドとともに渡されます。の内部P状態の変更は、コピーを変更するため、関係ありません。

于 2013-03-25T03:46:04.793 に答える
6

純粋メソッドの条件の1つは、その出力(戻り値)がその入力(引数)に完全に依存していることです。

その出力は入力引数と可変構造体の現在の値の両方に依存するため、.ToExactLocation()メソッドは純粋ではありません。

可変構造体は悪いので、Resharperはこれを好きではありません(それらを使用しないでください)。構造体の代わりにクラスを使用するようにコードを変更するか、構造体を再設計して.Xおよび.Yメンバーをコンストラクターでのみ設定できるようにすると、エラーがなくなると思います。

于 2013-03-25T03:45:51.687 に答える
4

答えを読んで、pure関数は必然的に数学の関数のようなものであることがわかりました。f(x) = x^2 + 2x + 10が0の場合、常に戻ります。10x

したがってToExactLocation()、オブジェクトが「純粋」と呼ばれるためには、最初の作成以降のオブジェクトの変更に関係なく、呼び出されるたびに同じ値を返す必要があります。

于 2013-03-25T03:46:03.613 に答える
2

「純粋関数」には2つの意味があります。1つは理論的(副作用なし/可変状態への依存なし)で、もう1つはReSharperが関数について考えるものです。

理論的な観点からは、関数は可変状態に依存するため、純粋ではありません。サンプル:

var someScreenLocation = new ScreenLocation(1,1);

var locationOne = someScreenLocation.ToExactLocation();
var locationTwo = someScreenLocation.ToExactLocation();
someScreenLocation.X = 3;
var locationThree = someScreenLocation.ToExactLocation();

メソッドを純粋にするために、入力に基づいてのみ結果を変更できます(引数がないため、この場合のようにまったく変更できません)。locationOneしかし、それとは同じであることがはっきりとわかりますlocationTwo(これまでのところ良い兆候です)が、残念ながらlocationThree、入力(関数への引数)が同じであっても異なります。

Xandを作成Y readonly(およびコンストラクターを追加)することで、理論的に純粋にすることができます。

変更後も、ReSharperはそれが純粋ではないと見なします。それを納得させるには、Pure属性を使用して純粋としてマークすることができます。

readonlyReSharperは、フィールドを持つクラスのコンストラクターでも「不純な」関数の使用をマークすることに注意してください。以下のサンプルは、ReSharperの警告を示しています。

struct Point
{
    public int X;
    public int Y;
    public Point(int x, int y){X = x;Y = y;}

    public void Mutate(){X++;}
    public Point TheoreticallyPure(){return new Point(1, 1);}
    [Pure] public Point MarkedPure(){ return new Point(1, 1);}
}

class WithReadonlyField
{
    public readonly Point P;
    public WithReadonlyField()
    {
        P = new Point();
        P.TheoreticallyPure();  // impure function on readonly value type
        P.MarkedPure(); // return value of pure not used
        P.Mutate();   // impure function on readonly value type - modifies P.
        P = new Point().MarkedPure(); // ok to modify P multiple times.
    }
    public void NormalMethod()
    {
        P.Mutate();   // impure function on readonly value type, no changes to P
    }
}

C#ではreadonly、コンストラクターの最後までフィールドを変更できますが、ReSharperは、そこでもすべての「不純な」関数の使用をマークします(コンストラクターの関数は、効果がない場合とは異なり、実際にはフィールドMutateの値を変更することに注意してください)。readonlyPNormalMethod

「宣言によって導入されたフィールドへの読み取り専用...割り当ては、宣言の一部として、または同じクラスのコンストラクターでのみ発生する可能性があります」

ほとんどの場合、ReSharperのこの動作は一貫性を保つためであり、完全に有効なコードを移動すると動作が完全に変わる場合を回避するためです。

于 2013-03-25T04:03:31.160 に答える
1

これを(いずれかのクラスの)静的メソッドとしてモデル化し、不純な警告を取り除く方がよいでしょう。他の回答がすでに理由をカバーしているため、説明は省略されています。

例:

public static ExactLocation ToExactLocation(ScreenLocation loc)
{
    return new ExactLocation {X = loc.X, Y = loc.Y};
}

または拡張メソッドを使用します

public static ExactLocation ToExactLocation(this ScreenLocation loc)
{
    return new ExactLocation {X = loc.X, Y = loc.Y};
}
于 2013-03-25T04:08:06.313 に答える
0

原因がよくわからないので、正しくフォーマットできればコメントとして入れておきます...

次のようなものが必要ではありませんか。

var someScreenLocation = MethodThatGivesAScreenLocation();
if (DestinationLocation.X == someScreenLocation.ToExactLocation().X &&
    DestinationLocation.Y == someScreenLocation.ToExactLocation().Y)
{
     // Do stuff
}
于 2013-03-25T03:50:02.600 に答える