Новое значение из ThreadLocal<IDisposable> после.Value.Dispose()

Есть ли встроенный ThreadLocal<T>-подобная конструкция для совместного использования объекта в каждом уникальном потоке, но воссоздания его, если исходное значение было уничтожено / уничтожено / сорвано / обнулено?

Вот моя попытка реализовать такое поведение с ConcurrentDictionary (ThreadLocalDisposable2 ниже), но я надеялся просто использовать ThreadLocal<T> (как в ThreadLocalDisposable1), однако я не могу получить Foo пройти тест, .Values.Remove(this) не делает то, что я надеялся, что это будет делать и до сих пор вызывает ObjectDisposedException,

public class Class1
{
    [Test]
    public void Foo()
    {
        using (var foo = ThreadLocalDisposable1.Get())
            foo.Foo();

        using (var foo = ThreadLocalDisposable1.Get())
            foo.Foo();
    }

    [Test]
    public void Bar()
    {
        using (var bar = ThreadLocalDisposable2.Get())
            bar.Foo();

        using (var bar = ThreadLocalDisposable2.Get())
            bar.Foo();
    }
}

[1]

public class ThreadLocalDisposable1 : IDisposable
{
    private Stream _foo;

    private static ThreadLocal<ThreadLocalDisposable1> _thread;

    static ThreadLocalDisposable1()
    {
        _thread = new ThreadLocal<ThreadLocalDisposable1>(() => new ThreadLocalDisposable1(), true);
    }

    private ThreadLocalDisposable1()
    {
        _foo = new MemoryStream();
    }

    public static ThreadLocalDisposable1 Get()
    {
        return _thread.Value;
    }

    public void Foo()
    {
        _foo.WriteByte(1);
    }

    public void Dispose()
    {
        //I do not think it means what I think it means
        _thread.Values.Remove(this);

        _foo.Dispose();
    }
}

[2]

public class ThreadLocalDisposable2 : IDisposable
{
    private Stream _foo;
    private int _thread;

    private static ConcurrentDictionary<int, ThreadLocalDisposable2> _threads;

    static ThreadLocalDisposable2()
    {
        _threads = new ConcurrentDictionary<int, ThreadLocalDisposable2>();
    }

    private ThreadLocalDisposable2(int thread)
    {
        _thread = thread;
        _foo = new MemoryStream();
    }

    public static ThreadLocalDisposable2 Get()
    {
        return _threads.GetOrAdd(Thread.CurrentThread.ManagedThreadId, i => new ThreadLocalDisposable2(i));
    }

    public void Foo()
    {
        _foo.WriteByte(1);
    }

    public void Dispose()
    {
        ThreadLocalDisposable2 thread;
        _threads.TryRemove(_thread, out thread);

        _foo.Dispose();
    }
}

Редактировать:

Просто чтобы уточнить, что я имею в виду, в основном я хочу, чтобы все поведение ThreadLocal но когда я звоню Dispose (по стоимости, ThreadLocalDisposable* с базовым Stream в этом примере не статический ThreadLocal сам) вывести этот ликвидированный экземпляр из обращения, т. е. при повторном вызове - создать новую ценность, как если бы это была совершенно новая нить, требующая нового экземпляра.

ThreadLocalDisposable1, [1], это пример класса того, что, я думаю, должно было сработать, кроме .Values.Remove(this) line не "выводит его из обращения" и заставляет создавать новый экземпляр для этого потока.

ThreadLocalDisposable2, [2], с ConcurrentDictionaryэто способ, которым я реализовал альтернативу ThreadLocal с поведением "вынуть из обращения", который я преследую.

Редактировать:

Это не реальный вариант использования, который я имею, просто общий пример, который я могу придумать, но если у вас есть, например, статический ThreadLocal<SqlConnection>или сокет, и он принудительно закрыт (и расположен в последнем блоке) - отбросьте тот экземпляр подключения и создайте новый прозрачно при повторном вызове.

1 ответ

Кажется, ты делаешь это намного сложнее, чем должно быть. Учти это:

public class MyClass: IDisposable
{
    private Stream _foo;

    public MyClass Get()
    {
        if (_foo == null)
        {
            _foo = new MemoryStream();
        }
    }

    public void Foo()
    {
        _foo.WriteByte(1);
    }

    public void Dispose()
    {
        if (_foo != null)
        {
            _foo.Dispose();
            _foo = null;
        }
    }
}

Теперь вы можете создать один из них:

ThreadLocal<MyClass> MyThing = new ThreadLocal<MyClass>();

И вы можете написать:

using (MyThing.Value.Get())
{
    // do stuff
}

Это кажется функционально эквивалентным тому, что вы пытаетесь сделать со своим ConcurrentDictionary вещи.

Тем не менее, кажется, что это то, что было бы лучше управлять другим способом. Я не знаю ваше приложение, поэтому не могу сказать наверняка, но кажется плохой идеей иметь объект с состоянием, такой как Stream или же SqlConnection как глобальная переменная. Обычно эти вещи зависят от задания, а не от потока, и поэтому должны передаваться в качестве параметров при запуске задания.

Другие вопросы по тегам