【问题标题】:C# conditional using block statementC# 条件使用块语句
【发布时间】:2010-12-08 16:17:38
【问题描述】:

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

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

【问题讨论】:

  • 为什么会尴尬?对我来说看起来很直接。
  • @Joel Etherton:可能是因为CheckExportDirectoryExists() 电话的重复。
  • 如果这是您的代码中最尴尬的部分,那么您已经过得很好。

标签: c# idisposable using-statement


【解决方案1】:

基于 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();
    }
}

同样,我仍然不确定我是否更喜欢原版...这真的取决于您需要这种模式的频率。

【讨论】:

  • 你的逻辑倒退了。交换 nullnew 表达式。
  • 原版更漂亮,但还是要 +1 :)
  • 我不知道在 using 语句中使用 null。
  • @John:我可能不会在 VS 中完成,但我不喜欢在 Stack Overflow 上进行代码包装,因为它的行很短。
  • +1 我真的很喜欢这个。之前没有考虑使用'null',它实际上让我在这里的情况更清楚,因为方法调用有一堆参数。
【解决方案2】:

using 语句是避免“finally”块的捷径,只有在它使代码更易于理解时才应使用。在您的情况下,我将编写以下代码。它可能不像其他一些版本那么简短,但更直接。

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

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

【讨论】:

  • 我同意,我认为这比 using 语句更能揭示意图 - 只是因为很明显访问是可选的,因为 finally 语句中的空检查 - 其中 using 语句混淆有点意思。
  • 我认为这是最好的答案,只是因为它在做需要做的事情的同时表现出意图的最佳工作,而不会以任何方式“聪明”。这将是 imo 惯用的 C# 方式。
  • 你在 try/finally 之外初始化你的一次性资源。这显然不是一个好主意。
  • 如果对象的构造函数失败,您将无法处理它。以下是来自微软网站的链接如何在幕后实现 using 语句:docs.microsoft.com/en-us/dotnet/csharp/language-reference/…
【解决方案3】:

如果你在很多方法中重复这个模式,你就可以打破这个模式

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

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

【讨论】:

  • 这很可能正是 OP 想要避免的。
【解决方案4】:
protected void ValidateExportDirectoryExists()
{
      var access = useNetworkAccess
          ? new Core.NetworkAccess(username, password, domain)
            : null;

      using (access)
      {
          CheckExportDirectoryExists();
      }
}

【讨论】:

    【解决方案5】:

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

    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 语句中使用。我不知道!

    【讨论】:

      【解决方案6】:

      如果类实现了 IDisposible 接口,那么使用作用域只会释放一个对象,所以是的,你需要实现 dispose 方法。

      【讨论】:

        【解决方案7】:

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

        我可以想象它会以另一种方式出现,我将投票给你现在拥有的这个版本。

        【讨论】:

          【解决方案8】:

          using 语句中包含的任何内容都将按照IDisposable 接口的指示调用IDispoable.Dispose。正如在 MSDN 上看到的 using...

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

          因此,如果您将自定义类型放在 using 语句中,它应该通过 IDisposable 接口适当地清理其资源。

          【讨论】:

            【解决方案9】:

            通过让您的类实现 IDisposable,dispose 方法仅在使用“using”语句时被调用。否则你必须显式调用 dispose。

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

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

            【讨论】:

              【解决方案10】:

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2011-07-18
                • 1970-01-01
                • 2020-09-13
                • 1970-01-01
                • 1970-01-01
                • 2012-09-02
                • 2011-09-22
                • 1970-01-01
                相关资源
                最近更新 更多