3

私はこの質問を読んでいて、この回答を読んでいました

これは実際には素晴らしい機能です。これにより、通常は非表示になっているもの、たとえばプライベートクラス変数にアクセスするクロージャを作成し、イベントなどへの応答として制御された方法で操作できるようになります。

変数のローカルコピーを作成し、それを使用することで、必要なものを非常に簡単にシミュレートできます。

この状況でLock()を実装する必要がありますか?

それはどのように見えるでしょうか?

Eric Lippertによると、コンパイラはコードを次のように見せます

private class Locals
{
  public int count;
  public void Anonymous()
  {
    this.count++;
  }
}

public Action Counter()
{
  Locals locals = new Locals();
  locals.count = 0;
  Action counter = new Action(locals.Anonymous);
  return counter;
}

ラムダと長い形式のコードはどのようになりますか?

4

4 に答える 4

5

ロックする理由がある場合lock、そうです。ステートメントをクロージャに入れることを妨げるものは何もありません。

たとえば、次のようにすることができます。

public static Action<T> GetLockedAdd<T>(IList<T> list)
{
    var lockObj = new object();
    return x =>
    {
        lock (lockObj)
        {
            list.Add(x);
        }
    }
}

コンパイラで生成されたコードに関して、これはどのように見えますか?自問してみてください:何が​​キャプチャされますか?

  • objectロックに使用されるローカル。
  • IList<T>渡された。

これらは、コンパイラによって生成されたクラスのインスタンスフィールドとしてキャプチャされます。したがって、結果は次のようになります。

class LockedAdder<T>
{
    // This field serves the role of the lockObj variable; it will be
    // initialized when the type is instantiated.
    public object LockObj = new object();

    // This field serves as the list parameter; it will be set within
    // the method.
    public IList<T> List;

    // This is the method for the lambda.
    public void Add(T x)
    {
        lock (LockObj)
        {
            List.Add(x);
        }
    }
}

public static Action<T> GetLockedAdd<T>(IList<T> list)
{
    // Initializing the lockObj variable becomes equivalent to
    // instantiating the generated class.
    var lockedAdder = new LockedAdder<T> { List = list };

    // The lambda becomes a method call on the instance we have
    // just made.
    return new Action<T>(lockedAdder.Add);
}

それは理にかなっていますか?

于 2011-01-24T05:59:07.327 に答える
2

はい、可能です。

ロックされたオブジェクトインスタンスを変更しないように注意してください。変更しないと、役に立たなくなります。

于 2011-01-24T05:04:34.270 に答える
1

あなたはこのような機能を持つことができます:

static Func<int> GetIncrementer()
{
    object locker = new object();
    int i = 0;
    return () => { lock (locker) { return i++; } };
}

これを呼び出すと、スレッドセーフな方法で内部カウンターをインクリメントする関数が返されます。このような関数を実装するための最良の方法ではありませんが、クロージャ内のロックを示しています。

于 2011-01-24T05:43:19.803 に答える
0

私はインターネット旅行でこれに出くわしました、そしてそれが非常に古い質問であることを知っています、しかし私はそれに別の答えを提案したいと思いました。

ラッパー関数を使用してラムダ内をロックすることができます。これにより、比較的洗練された構文が可能になります。

ヘルパー関数(静的クラス内)は次のとおりです。

public static class Locking
{
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    [DebuggerNonUserCode, DebuggerStepThrough]
    public static T WithLock<T>(this object threadSync, Func<T> selector)
    {
        lock (threadSync)
        {
            return selector();
        }
    }
}

そして、これがあなたがそれを使う方法です:

private readonly object _threadSync = new object();
private int _myProperty;

public int MyProperty
    => _threadSync.WithLock(() => _myProperty);
于 2018-06-27T09:28:24.967 に答える