将“使用”用于资源处理以外的事物

时间:2013-05-29 13:31:13

标签: c# using-statement

我们都知道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;
   }
}

然后可以这样使用类,而不必担心在完成后还原Cursor。

public void TimeIntensiveMethod()
{
   using (CursorHelper ch = new CursorHelper(Cursors.WaitCursor))
   {
      // something that takes a long time to complete
   }
}

这是using声明的恰当用途吗?

5 个答案:

答案 0 :(得分:5)

实际上using只是try/finally的语法糖,所以为什么不像以下那样只做简单的尝试/终结...

try
{
    // do some work
}
finally
{
    // reset to some previous state
}

imho实施 Dispose 方法重置为某种状态会产生误导,特别是如果您的代码有消费者。

答案 1 :(得分:5)

(ab)以这种方式使用using语句肯定有先例,例如ASP.NET MVC框架中的FormExtensions.BeginForm。这会在处置时呈现<form>结束标记,其主要目的是在MVC视图中启用更简洁的语法。即使抛出异常,Dispose方法也会尝试呈现结束标记,这有点奇怪:如果在呈现表单时抛出异常,您可能不希望尝试呈现结束标记。 / p>

另一个例子是log4net框架中的(现已弃用的)NDC.Push方法,该方法返回IDisposable,其目的是弹出上下文。

有些纯粹主义者会说这是一种虐待,我建议你根据具体情况自行判断。 就个人而言,我没有看到你的例子渲染沙漏光标有什么问题。

discussion linked in a comment by @I4V有一些有趣的意见 - 包括反对无处不在的Jon Skeet的这类“滥用”的论据。

答案 2 :(得分:4)

我反对这一点,并认为这是一种虐待。我也认为C ++中的RAII是一个糟糕的主意。我知道我在这两个职位上占少数。

这个问题是重复的。有关我认为这是对for语句的无理滥用的详细原因,请参阅:https://stackoverflow.com/a/2103158/88656

答案 3 :(得分:2)

不,不适合使用using和/或Dispose。该模式具有非常明确的用途(“定义释放已分配资源的方法。”),这不是它。任何使用此代码的未来开发人员都会以这种邪恶的蔑视来看待它。

如果你想要这个 kind 行为然后实现事件并公开它们,调用代码可以订阅它们并管理游标,如果需要,否则游标应该可以通过一般参数来管理使用BeginEnd方法(尽管这些命名约定通常保留用于方法的异步实现,但是你得到了图片) - 以这种方式进行黑客攻击实际上并没有给你带来什么。

答案 4 :(得分:-1)

我认为以一种除了处理对象之外的方式使用-Disposable的东西是有意义的。当然,这取决于上下文和用法。如果导致代码更易读,那就没关系。

我曾在一个单位的工作中使用它&amp;存储库模式实现如:

public class UnitOfWork: IDisposable  {
    // this is thread-safe in actual implementation
    private static Stack<UnitOfWork> _uowStack = new Stack<UnitOfWork>();
    public static UnitOfWork Current {get { return _uowStack.Peek(); }} 

    public UnitOfWork() {
        _uowStack.Push(this);
    }

    public void Dispose() {
        _ouwStack.Pop();
    }

    public void SaveChanges() {
        // do some db operations
    }
}

public class Repository {
    public void DoSomething(Entity entity) {
        // Do Some db operations         

        UnitOfWork.Current.SaveChanges();
    }
}

通过这种实现,可以保证嵌套操作将使用相应的UnitOfWork而不传递参数。用法就像。

using (new UnitOfWork()) 
{
    var repo1 = new UserRepository();
    // Do some user operation

    using (new UnitOfWork())  
    {
         var repo2 = new AccountingRepository();
         // do some accounting
    }

    var repo3 = new CrmRepository();
    // do some crm operations
}

在此示例中,repo1和repo3使用相同的UnitOfWork,而repo2使用不同的存储库。读者读到的是&#34;使用新的工作单元&#34;这很有道理。