我可以重用通过“using”语句处理的对象

时间:2013-11-05 11:31:14

标签: c# locking idisposable using

我正在创建一个类,比如说LockHolder,以简化需要逻辑的锁。它实现了IDisposable接口,因此我可以像这样使用它:

using(LockHolderCreater.Create(lockObject, waittime))
{
    //do something
}

LockHolder的Dispose方法释放lockObject(通过Monitor.Exit)(如果已获得)(通过Monitor.TryEnter)。 如果我每次调用LockHolderCreater.Create时创建一个新的LockHolder对象,那都可以正常工作,但这会产生太多的LockHolder实例。因此,我编写LockHolderCreater来维护一个LockHolder对象列表,以便重用它们。现在我面临着太多问题:

首先,在调试时,我发现在输出窗口中有很多这样的消息:“System.dll中出现类型'System.ObjectDisposedException'的第一次机会异常”。如果“using”语句只是调用Dispose方法,我可以阻止这种异常吗?

其次,更重要的是,如果我重用LockerHolder实例,在应用程序启动后的某个早期,当我尝试在Dispose方法中释放锁时会抛出SynchronizationLockException异常,说“对象同步方法是从一个不同步的代码块中调用。“我检查了我的逻辑,但我认为两个线程不会同时使用一个LockHolder实例。这可能与上面提到的ObjectDisposedException有关吗?

关于答案

我没有直接回答我的问题,但Marc Gravell的答案使其不那么重要。

3 个答案:

答案 0 :(得分:3)

你应该这样做:可能不会,除非您完全控制类型的非常特殊情况。

可以你这样做:这完全取决于实现 - 你当然不希望随机应用于任意类型。但是,如果类型(作为清理的一部分)返回到某个池并重新初始化并重新使用,那么它将工作。但是:如果// do something代码在某个地方泄露了引用,则存在问题。

  

可以防止这种异常吗?

是:在处理完对象后不要访问该对象

  

说“从非同步的代码块调用了对象同步方法。”

我想知道 - 你可能在这里使用await吗?还是迭代器块?或类似的东西?如果进入和退出代码在不同的线程上运行,它将失败。

如果您的目的是尽量减少LockerHolder的分配,那么有一种更好的方法:使用struct

using System;

struct Foo : IDisposable
{
    public Foo(string msg)
    {
        Console.WriteLine("Init: " + msg);
    }
    public void Dispose()
    {
        Console.WriteLine("Disposed");
    }

}

static class Program
{
    static void Main()
    {
        Console.WriteLine("Before");
        using (new Foo("Hi"))
        {
            Console.WriteLine("Do stuff");
        }
        Console.WriteLine("After");
    }
}

此处Main方法使用constrained-call编译Dispose,这意味着不会包含

请注意,要使其正常工作,LockHolderCreater.Create方法必须返回结构本身 - 它不能只返回IDisposable

答案 1 :(得分:0)

在using语句的控制表达式中声明变量会将变量的范围限制在using语句中。

选中此answer

答案 2 :(得分:0)

滥用using声明是个坏主意。它不是用作通用的“自动撤销”。它仅用于确保处理非托管资源(如数据库连接)。