我从阅读MSDN文档中了解到,IDisposable接口的"主要"用途是清理非托管资源.
对我来说,"非托管"意味着数据库连接,套接字,窗口句柄等等.但是,我已经看到了Dispose()实现该方法以释放托管资源的代码,这对我来说似乎是多余的,因为垃圾收集器应该照顾那对你而言.
例如:
public class MyCollection : IDisposable
{
private List<String> _theList = new List<String>();
private Dictionary<String, Point> _theDict = new Dictionary<String, Point>();
// Die, clear it up! (free unmanaged resources)
public void Dispose()
{
_theList.clear();
_theDict.clear();
_theList = null;
_theDict = null;
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,这是否使得垃圾收集器可以使用的内存MyCollection比通常更快?
编辑:到目前为止,人们已经发布了一些使用IDisposable清理非托管资源(例如数据库连接和位图)的好例子.但是假设_theList在上面的代码中包含了一百万个字符串,并且你想现在释放那个内存,而不是等待垃圾收集器.上面的代码会实现吗?
接口的目的IDisposable是以有序的方式释放非托管资源.它与using定义范围的关键字密切相关,该关键字在有问题的资源被处置之后.
因为这种机制非常简洁,所以我一直试图让类实现IDisposable能够以其不适合的方式滥用这种机制.例如,可以实现类来处理嵌套的上下文,如下所示:
class Context : IDisposable
{
// Put a new context onto the stack
public static void PushContext() { ... }
// Remove the topmost context from the stack
private static void PopContext() { ... }
// Retrieve the topmost context
public static Context CurrentContext { get { ... } }
// Disposing of a context pops it from the stack
public void Dispose()
{
PopContext();
}
}
Run Code Online (Sandbox Code Playgroud)
调用代码的用法可能如下所示:
using (Context.PushContext())
{
DoContextualStuff(Context.CurrentContext); …Run Code Online (Sandbox Code Playgroud) 我正在使用数据库,有一种情况我想关闭它中的一个功能.关闭该功能看起来像这样......
DatabaseContext.Advanced.UseOptimisticConcurrency = false;
打开它也很容易.这个功能很好.但我对某事感到好奇,并想探索它......
是否有可能将它包装在"使用"块中,就像处理像dispose和unsafe这样的东西一样?例如...
using(DatabaseContext.Advanced.UseOptimisticConcurrency = false){
// do things!
}
// the feature is turned back on automatically here!
Run Code Online (Sandbox Code Playgroud)
在StackOverflow的优秀人才的帮助下,我现在已经完成了我想要的工作.再次感谢.这是我的工作代码.不要介意详细的文档.我只是那种在我脑海中输入所有内容的程序员.
using System;
namespace Raven.Client {
/// <summary>
/// Used to emulate a series of transactions without optimistic concurrency in RavenDB
/// </summary>
/// <remarks>
/// This has been flagged as an 'abuse' of the IDisposable interface, which is something I will learn more about
/// and try to find a better solution. The purpose of this …Run Code Online (Sandbox Code Playgroud) 假设我想强制执行一条规则:
每次在函数中调用"StartJumping()"时,必须在返回之前调用"EndJumping()".
当开发人员编写代码时,他们可能只是忘记调用EndSomething - 所以我想让它易于记忆.
我只能想到一种方法:它滥用"using"关键字:
class Jumper : IDisposable {
public Jumper() { Jumper.StartJumping(); }
public void Dispose() { Jumper.EndJumping(); }
public static void StartJumping() {...}
public static void EndJumping() {...}
}
public bool SomeFunction() {
// do some stuff
// start jumping...
using(new Jumper()) {
// do more stuff
// while jumping
} // end jumping
}
Run Code Online (Sandbox Code Playgroud)
有一个更好的方法吗?
我有一个InfoPath表单,我需要有条件地禁用它的OnChange事件.由于在表单加载后无法绑定事件处理程序,因此我不得不依赖一个全局计数器来指示是否应该执行OnChange事件.在每个OnChange事件中,我在执行任何操作之前检查SuppressEventsCount == 0.为了在执行某个函数或其他函数期间抑制事件,我只需设置SuppressEventsCount ++,并且 - 当函数退出时再次.这样做的最大问题是它不是例外.所以我有一个好主意将SuppressEvents计数器包装在一个实现iDisposable的类中
using(SuppressEvents s = new SuppressEvents()){
// OnChange events fired here are ignored
} // OnChange events enabled again
Run Code Online (Sandbox Code Playgroud)
这是有效的,但它仍然不如c ++解决方案那么理想,它根本不需要使用"using"指令.
有没有办法:
我们都知道该using语句非常适合您想要及时清理的资源,例如打开文件或数据库连接.
我想知道在资源清理不是Dispose()方法的目标而是重置为先前状态的情况下使用该语句是否是一件好事.
例如,一个允许using语句包装过程的类,该过程需要花费大量时间并将Cursor更改为等待状态.
class CursorHelper : IDisposable
{
readonly Cursor _previousState;
public CursorHelper(Cursor newState)
{
_previousState = Cursor.Current;
Cursor.Current = newState;
}
public void Dispose()
{
Cursor.Current = _previousState;
}
}
Run Code Online (Sandbox Code Playgroud)
然后可以这样使用类,而不必担心在完成后还原Cursor.
public void TimeIntensiveMethod()
{
using (CursorHelper ch = new CursorHelper(Cursors.WaitCursor))
{
// something that takes a long time to complete
}
}
Run Code Online (Sandbox Code Playgroud)
这是否适用于该using声明?
出于方便和安全的原因,我想使用该using语句来分配和释放来自/到池的对象
public class Resource : IDisposable
{
public void Dispose()
{
ResourcePool.ReleaseResource(this);
}
}
public class ResourcePool
{
static Stack<Resource> pool = new Stack<Resource>();
public static Resource GetResource()
{
return pool.Pop();
}
public static void ReleaseResource(Resource r)
{
pool.Push(r);
}
}
Run Code Online (Sandbox Code Playgroud)
和访问池一样
using (Resource r = ResourcePool.GetResource())
{
r.DoSomething();
}
Run Code Online (Sandbox Code Playgroud)
我找到了一些关于滥用using和Dispose()范围处理的主题,但所有这些主题都包含在内using (Blah b = _NEW_ Blah()).
在离开使用范围但保留在池中之后,不会释放对象.
如果using语句只是简单地扩展到一个简单,try finally Dispose()这应该工作正常但是在幕后会发生更多的事情,或者在未来的.Net版本中这种情况不会发生吗?
与此问题类似,我希望将IDisposable用于其他设计之外的其他内容.
这个应用程序并不是非常相关,但仅仅是一个很好的例子:我有一个Windows Forms应用程序,我实现了一个Undo设计模式.通常,这是通过拦截UI元素中的"Value Changed"事件来完成的.对于DataGridView,CellEndEdit等等.但是在某些情况下,我会以编程方式更改数据,并且我希望每个撤消操作都跟踪它们,而不跟踪它们.
我有办法完成所有这些,但我在计算中管理我的"我应该撤消"逻辑:
private int _undoOverrides = 0;
public bool ShouldUndo { get { return _undoOverrides < 1; } }
public void DoNotUndo() { ++_undoOverrides; }
public void ResumeUndo() { --_undoOverrides; }
Run Code Online (Sandbox Code Playgroud)
现在,这种方法运行良好,但您必须记住ResumeUndo()在这样的业务逻辑结束时调用DoNotUndo().我想:
也许我不是太愚蠢的搞砸了,但是如果我不得不在代码中公开这个接口我会传递下去呢?如果可能的话,我想编译器可以为我处理这个问题.
我正在考虑使用一个实现IDisposable此类的类.这样,我的代码的用户可以使用一个using块,从不担心家务杂务.这是我到目前为止:
private static int _refCount = 0;
public static int ReferenceCount { get { return _refCount; } }
class HallPass : IDisposable
{
protected bool bActive; …Run Code Online (Sandbox Code Playgroud) C#是否有办法暂时更改特定范围内变量的值,并在范围/块的末尾自动将其还原?
例如(不是真正的代码):
bool UpdateOnInput = true;
using (UpdateOnInput = false)
{
//Doing my changes without notifying anyone
Console.WriteLine (UpdateOnInput) // prints false
}
//UpdateOnInput is true again.
Run Code Online (Sandbox Code Playgroud)
编辑:
我想要上述的原因是因为我不想这样做:
UpdateOnInput = false
//Doing my changes without notifying anyone
Console.WriteLine (UpdateOnInput) // prints false
UpdateOnInput = true
Run Code Online (Sandbox Code Playgroud) 我只是通过使用扩展方法回答了一个非常简单的问题.但在写完之后我记得你不能从事件处理程序取消订阅lambda.
到目前为止没有大问题.但是这一切如何在扩展方法中表现出来?
下面是我的代码再次剪断.所以任何人都可以启发我,如果你多次调用这个扩展方法会导致无数的计时器在内存中徘徊?
我会说不,因为定时器的范围在这个函数内是有限的.所以在离开后没有其他人有这个对象的引用.我只是有点不确定,因为我们在静态类中的静态函数中.
public static class LabelExtensions
{
public static Label BlinkText(this Label label, int duration)
{
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
timer.Interval = duration;
timer.Tick += (sender, e) =>
{
timer.Stop();
label.Font = new Font(label.Font, label.Font.Style ^ FontStyle.Bold);
};
label.Font = new Font(label.Font, label.Font.Style | FontStyle.Bold);
timer.Start();
return label;
}
}
Run Code Online (Sandbox Code Playgroud)
只是为了澄清我使用的是System.Windows.Forms.Timer.所以从您的答案看来,特别是使用这个计时器类只是正确的选择因为它做了任何事情,就像我在这种情况下所期望的那样.如果你在这种情况下尝试另一个计时器类,你可能会遇到麻烦,正如马修发现的那样.此外,我发现了一种方法,通过使用了WeakReference ■如果我的对象是活着还是没有.
经过一点点的睡眠和更多的思考后,我还对我的测试仪做了另一个改动(下面回答)我刚刚GC.Collect()在最后一行之后添加了一个并将持续时间设置为10000.启动BlinkText()几次之后我一直按下我的按钮2到获取当前状态并强制进行垃圾回收.而且看起来所有的计时器都会在调用Stop()方法后被销毁.因此,当我的BlinkText已经离开并且计时器正在运行时,垃圾收集也不会导致任何问题.
因此,经过你所有的良好反应和更多的测试后,我可以高兴地说,它只是做了它应该做的事情而不会将计时器留在记忆中,也不会在计时器完成工作之前扔掉它们.