61

私はこのコードを持っています:

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

    private Lazy<int> lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
    public int Sum{ get { return lazyGetSum.Value; } }

}

このエラーが表示されます:

フィールド初期化子は、非静的フィールド、メソッド、またはプロパティを参照できません。

レイジーを介して非静的メンバーにアクセスすることは非常に合理的だと思いますが、これを行う方法は?

* 編集 *

受け入れられた回答は問題を完全に解決しますが、問題の詳細で詳細な理由を確認するには、いつものように、Joh Skeet's answerを読むことができます。

4

6 に答える 6

99

コンストラクターに移動できます。

private Lazy<int> lazyGetSum;
public MyClass()
{
   lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
}

問題の理由の詳細については、以下の @JohnSkeet の回答を参照してください。 Lazy<T> または任意のラムダ式を介して非静的メンバーにアクセスする

于 2012-12-25T09:36:59.177 に答える
63

問題の簡略版は次のとおりです。

class Foo
{
    int x = 10;
    int y = this.x;
}

そして、少し単純化されていないもの:

class Foo
{
    int x = 10;
    Func<int> y = () => this.x;
}

(this通常は暗黙的ですが、わかりやすくするためにここでは明示的にしています。)

最初のケースでは、の使用thisは非常に明白です。

2 番目のケースでは、ラムダ式のために延期されているため、少しわかりにくくなっています。ただし、まだ許可されていません...コンパイラはthis、次のように、ターゲットとして使用されるデリゲートを構築しようとするためです。

class Foo
{
    int x = 10;
    Func<int> y = this.GeneratedMethod;

    private int GeneratedMethod()
    {
        return x;
    }
}

これは、C# 5 仕様のセクション 10.5.5.2 で禁止されています。

インスタンス フィールドの変数初期化子は、作成中のインスタンスを参照できません。

最も簡単な修正は、参照できるコンストラクタ本体に初期化を配置することthisです。だからあなたのコードで:

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

    private Lazy<int> lazyGetSum;

    public MyClass()
    {
        lazyGetSum = new Lazy<int>(() => X + Y);
    }

    public int Sum{ get { return lazyGetSum.Value; } }
}

ラムダ式も簡略化したことに注意してください。使用する価値はほとんどありませんnew Func<int>(...)

于 2012-12-25T09:39:27.553 に答える
3

エラーは、何が間違っているかを正確に示しています。フィールド初期化子でプロパティにアクセスすることはできません。

クラスが次のようになっているとします。

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

    private Lazy<int> lazyGetSum = new Lazy<int>(new Func<int>(() => 2 + 3));
    public int Sum { get { return lazyGetSum.Value; } }

}

その後、問題なくコンパイルされます。あなたのコードでは、フィールドの初期化でプロパティ X と Y にアクセスしているためです。エラーが発生しています。

必要に応じて、コンストラクターで初期化することもできます。

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

    private Lazy<int> lazyGetSum; 
    public int Sum { get { return lazyGetSum.Value; } }

    public MyClass()
    {
        lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
    }

}
于 2012-12-25T09:36:34.580 に答える
0

staticこのように使用するには、フィールドを定義する必要があると思います。

public  class MyClass
    {
        public static int X { get; set; }
        public static int Y { get; set; }

        private Lazy<int> lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
        public int Sum { get { return lazyGetSum.Value; } }
    }

もちろん、フィールドを初期化する必要があります。他の方法ではできません。

編集:または、定義せずにコンストラクターで定義することもできますstatic

public MyClass()
    {
        lazyGetSum = new Lazy<int>(new Func<int>(() => X + Y));
    }

private Lazy<int> lazyGetSum; 
public int Sum { get { return lazyGetSum.Value; } }
于 2012-12-25T09:36:28.643 に答える
0

非静的メソッドを使用する場合。Lazyのようなコンストラクターではなく、.Value で Func パラメーターを取得するLazy self の代替ビルドを使用することもできます。

コードは次のようになります。

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

    private readonly LazyValue<int> lazyGetSum = new LazyValue<int>();
    public int Sum { get { return lazyGetSum.GetValue(() => X + Y); } }
}

プロパティにプロパティを実装します。期待通りの場所で、

于 2014-03-22T19:04:40.687 に答える