我正在创建一个类,比如说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的答案使其不那么重要。
答案 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
声明是个坏主意。它不是用作通用的“自动撤销”。它仅用于确保处理非托管资源(如数据库连接)。