Подтвердить что ты не робот

С# условное использование оператора блока

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

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

Ответ 1

Один вариант, который несколько неприятен, но будет работать, исходя из того, что компилятор С# вызывает Dispose, только если ресурс не равен 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();
    }
}

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

Ответ 2

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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] Просто увидел в Jon ответ, что null может использоваться в операторе using. Я понятия не имел!

Ответ 5

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

      using (access)
      {
          CheckExportDirectoryExists();
      }
}

Ответ 6

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

Ответ 7

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

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

Ответ 8

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

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

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

Ответ 9

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

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

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

Ответ 10

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