C#条件使用块语句

时间:2010-12-08 16:17:39

标签: c# idisposable using-statement

我有以下代码,但很尴尬。我怎么能更好地构建它?我是否必须使我的消费类实现IDisposable并有条件地构建网络访问类并在完成后处置它?

    protected void ValidateExportDirectoryExists()
    {
        if (useNetworkAccess)
        {
            using (new Core.NetworkAccess(username, password, domain))
            {
                CheckExportDirectoryExists();
            }
        }
        else
        {
            CheckExportDirectoryExists();
        }
    }

10 个答案:

答案 0 :(得分:58)

基于C#编译器调用Dispose only if the resource is non-null

这一事实,有一种选择,有点令人讨厌但可行
protected void ValidateExportDirectoryExists()
{
    using (useNetworkAccess 
               ? new Core.NetworkAccess(username, password, domain)
               : null)
    {
        CheckExportDirectoryExists();
    }
}

另一种方法是编写一个返回null或NetworkAccess的静态方法:

private Core.NetworkAccess CreateNetworkAccessIfNecessary()
{
    return useNetworkAccess
        ? new Core.NetworkAccess(username, password, domain)) : null;
}

然后:

protected void ValidateExportDirectoryExists()
{
    using (CreateNetworkAccessIfNecessary())
    {
        CheckExportDirectoryExists();
    }
}

同样,我仍然不确定我不喜欢原版......这实际上取决于你需要这种模式的频率。

答案 1 :(得分:7)

如果你在许多方法中重复这种模式,你可以打破模式

protected void OptionalNetworkCall(Action action)
{
    if (useNetworkAccess)
    {
        using (new Core.NetworkAccess(username, password, domain))
        {
            action();
        }
    }
    else
    {
        action();
    }
}

protected void ValidateExportDirectoryExists()
{
    OptionalNetworkCall(CheckExportDirectoryExists);
}

答案 2 :(得分:4)

using语句是避免“finally”块的快捷方式,只有在使代码更容易理解时才能使用。在你的情况下,我会写下面的代码。它可能不像其他一些版本那么简短,但更为直接。

protected void ValidateExportDirectoryExists()
{
    Core.NetworkAccess access = useNetworkAccess ? new Core.NetworkAccess(username, password, domain) : null;    

    try
    {
        CheckExportDirectoryExists()
    }
    finally
    {
       if (access != null)
       {
           access.Dispose();
       }
    }
}

答案 3 :(得分:2)

protected void ValidateExportDirectoryExists()
{
      var access = useNetworkAccess
          ? new Core.NetworkAccess(username, password, domain)
            : null;

      using (access)
      {
          CheckExportDirectoryExists();
      }
}

答案 4 :(得分:1)

我不知道它是否“更好”,但你可以使用null对象模式并拥有一个“null”一次性网络访问对象。像这样:

protected void ValidateExportDirectoryExists()     
{
  using (GetNetworkAccess(username, password, domain))
  {                 
    CheckExportDirectoryExists();
  }
} 

protected IDisposable GetNetworkAccess(string username, string password, string domain)
{
  return useNetworkAccess ? new Core.NetworkAccess(username, password, domain) : new NullNetworkAccess(username, password, domain);
}

internal class NullNetworkAccess : IDisposable
{
  internal NullNetworkAccess(string username, string password, string domain)
  {
  }

  public void Dispose()
  {
  }
}

这可能太可爱了。

[编辑] 刚刚在Jon的回答中看到null可以在using语句中使用。我不知道!

答案 5 :(得分:0)

使用scope只会在类实现IDisposible接口时处理一个对象,所以是的,你需要实现dispose方法。

答案 6 :(得分:0)

如果代码简单,我想这真的是化妆品问题。

我可以想象它是如何看待另一种方式,我的投票将是你现在拥有的这个版本。

答案 7 :(得分:0)

无论using语句中包含什么内容,IDispoable.Dispose接口都会调用它IDisposable。正如MSDN上using ...

所见
  

提供方便的语法   确保正确使用IDisposable   对象。

因此,如果您在using语句中放置自定义类型,则应通过IDisposable接口正确清理其资源。

答案 8 :(得分:0)

通过让您的类实现IDisposable,只有在使用“using”语句时才会调用dispose方法。否则你必须明确地调用dispose。

通常,IDisposable由管理垃圾收集器之外的内存消耗的对象实现(例如,使用非托管代码)。它提供了一种清理任何消耗内存的方法。

只要您的NetworkAccess类实现了IDisposable,就会在using语句的范围完成后立即调用dispose方法。如果是托管代码,则无需处理它。让垃圾收集器完成它的工作。

答案 9 :(得分:0)

使用您自己的try / finally块,它执行与'using'类似的逻辑,但只有在设置了useNetworkAccess时才执行dispose。请注意,如果useNetworkAccess可能受到其他线程的影响,则应复制其值并使用该副本创建资源并进行处置。