C # условное использование оператора блока - PullRequest
30 голосов
/ 08 декабря 2010

У меня есть следующий код, но это неудобно.Как я мог бы лучше структурировать это?Нужно ли заставлять мой потребительский класс реализовывать IDisposable и условно создавать класс доступа к сети и утилизировать его, когда я закончу?

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

Ответы [ 10 ]

58 голосов
/ 08 декабря 2010

Один вариант, который несколько неприятен, но сработает, основан на том факте, что компилятор C # вызывает Dispose , только если ресурс ненулевой :

protected void ValidateExportDirectoryExists()
{
    using (useNetworkAccess 
               ? new Core.NetworkAccess(username, password, domain)
               : null)
    {
        CheckExportDirectoryExists();
    }
}

Другой альтернативой было бы написать статический метод, который бы возвратил либо нуль, либо NetworkAccess:

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

Затем:

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

Опять же, я все еще не уверен, что не предпочитаюоригинал ... это действительно зависит от того, как часто вам нужен этот шаблон.

7 голосов
/ 08 декабря 2010

Если вы повторите этот паттерн во многих методах, вы можете разбить паттерн

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

protected void ValidateExportDirectoryExists()
{
    OptionalNetworkCall(CheckExportDirectoryExists);
}
4 голосов
/ 08 декабря 2010

Оператор using является ярлыком, позволяющим избежать блоков "finally", и должен использоваться только тогда, когда он облегчает выполнение кодаВ вашем случае я бы написал следующий код.Это может быть не так кратко, как в некоторых других версиях, но гораздо проще.

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

    try
    {
        CheckExportDirectoryExists()
    }
    finally
    {
       if (access != null)
       {
           access.Dispose();
       }
    }
}
2 голосов
/ 08 декабря 2010
protected void ValidateExportDirectoryExists()
{
      var access = useNetworkAccess
          ? new Core.NetworkAccess(username, password, domain)
            : null;

      using (access)
      {
          CheckExportDirectoryExists();
      }
}
1 голос
/ 08 декабря 2010

Я не знаю, «лучше» ли это, но вы могли бы использовать шаблон нулевого объекта и иметь «нулевой» одноразовый объект доступа к сети.Примерно так:

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()
  {
  }
}

Это, наверное, слишком мило для собственной пользы.

[EDIT] Только что увидел в ответе Джона, что null может использоваться в выражении using.Я понятия не имел!

0 голосов
/ 08 декабря 2010

Используйте свой собственный блок try / finally, который выполняет логику, аналогичную «using», но выполняет удаление только в том случае, если установлен useNetworkAccess.Обратите внимание, что если на useNetworkAccess могут повлиять другие потоки, вам следует скопировать его значение и использовать эту копию как для создания ресурса, так и для его утилизации.

0 голосов
/ 08 декабря 2010

Если ваш класс реализует IDisposable, метод dispose вызывается только при использовании оператора «using». В противном случае вы должны явно вызвать dispose.

Обычно IDisposable реализуется объектами, которые управляют потреблением памяти вне сборщика мусора (как, например, использование неуправляемого кода). Предоставляет способ очистки любой использованной памяти.

Пока ваш класс NetworkAccess реализует IDisposable, метод dispose будет вызываться, как только завершится область действия оператора using. Если это управляемый код, то избавляться от него не нужно. Просто позвольте сборщику мусора выполнить свою работу.

0 голосов
/ 08 декабря 2010

Все, что заключено в оператор использования, будет иметь IDispoable.Dispose, вызываемый как диктуется интерфейсом IDisposable. Как видно на MSDN для using ...

Предоставляет удобный синтаксис, который обеспечивает правильное использование IDisposable объекты.

Поэтому, если вы поместите пользовательский тип в оператор using, он должен соответствующим образом очистить свои ресурсы через интерфейс IDisposable.

0 голосов
/ 08 декабря 2010

Я думаю, это действительно вопрос косметики, если код такой простой.

Я могу представить, как это могло бы выглядеть по-другому, и мой голос будет за ту версию, которую вы сейчас имеете.

0 голосов
/ 08 декабря 2010

при использовании области действия объект будет удален только в том случае, если класс реализует интерфейс IDisposible, так что да, вам нужно реализовать метод dispose.

...