Pytanie Warunek C # za pomocą instrukcji block


Mam następujący kod, ale jest niezręczny. Jak mogę go lepiej uporządkować? Czy muszę sprawić, aby moja klasa używała implementacji IDisposable i warunkowo konstruowała klasę dostępu do sieci i usuwała ją po zakończeniu?

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

25
2017-12-08 16:17


pochodzenie


Dlaczego jest niezręcznie? Wygląda całkiem prosto do mnie. - Joel Etherton
@ Joel Etherton: Prawdopodobnie z powodu powtórzenia tego CheckExportDirectoryExists() połączenie. - BoltClock♦
Jeśli jest to najbardziej niezręczny fragment twojego kodu, jesteś bardzo zamożny. - Nate
@Nate. lol - uwielbiam to! - David


Odpowiedzi:


Jedna opcja, która jest nieco nieprzyjemna, ale działa, w oparciu o fakt, że kompilator C # wywołuje Dispose tylko jeśli zasób ma wartość inną niż null:

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

Inną alternatywą byłoby napisanie statycznej metody, która zwróciła wartość zerową lub NetworkAccess:

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

Następnie:

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

Ponownie, nadal nie jestem pewien, czy nie wolę oryginału ... to naprawdę zależy od tego, jak często potrzebujesz tego wzoru.


52
2017-12-08 16:20



Masz logikę tam do tyłu. Zamiana null i new wyrażenie. - cdhowie
Oryginał jest ładniejszy, ale +1 tak czy inaczej :) - Daniel Mošmondor
@cdhowie: Naprawiono, dzięki :) - Jon Skeet
Nie wiedziałem, że o użyciu null w instrukcji using. - wageoghe
+1, ponieważ umieściłeś ? i : na własnych liniach. :) - John Gietzen


Jeśli powtórzysz ten wzór na wielu metodach, możesz przerwać wzór

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

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

7
2017-12-08 16:23





Instrukcja using jest skrótem służącym do unikania blokad "w końcu" i powinna być używana tylko wtedy, gdy ułatwia kod. W twoim przypadku napiszę poniższy kod. Może nie być tak krótki jak niektóre inne wersje, ale jest znacznie prostszy.

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

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

4
2017-12-08 17:02



Zgadzam się, myślę, że jest to więcej intencji ujawniające niż użycie oświadczenia - tylko dlatego, że od razu oczywiste jest, że dostęp jest opcjonalny, z powodu tego zerowego sprawdzenia w ostatecznym oświadczeniu - gdzie jako wypowiedzenie użycia nieco zaciemnia intencję. - Bittercoder
Uważam, że jest to najlepsza odpowiedź tylko dlatego, że najlepiej pokazuje ona intencje podczas robienia tego, co jest potrzebne, bez bycia "sprytnym" w żaden sposób. to byłby idiomatyczny C # way imo. - Mike Corcoran


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

      using (access)
      {
          CheckExportDirectoryExists();
      }
}

2
2017-12-08 16:31





Nie wiem, czy jest "lepszy", ale można użyć pustego wzorca obiektu i mieć "zerowy" jednorazowy obiekt dostępu do sieci. Coś takiego:

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

Jest to prawdopodobnie zbyt słodkie dla własnego dobra.

[EDYTOWAĆ] Właśnie widziałem w odpowiedzi Jona, że ​​wartość null może być użyta w instrukcji użycia. Nie mam pojęcia!


1
2017-12-08 16:27





używanie zakresu spowoduje tylko usunięcie obiektu, jeśli klasa implementuje interfejs IDisposible, więc tak, musisz zaimplementować metodę dispose.


0
2017-12-08 16:20





Sądzę, że to naprawdę kwestia kosmetyków, jeśli kod jest tak prosty.

Mogę sobie wyobrazić, jak mogłoby to wyglądać inaczej, a mój głos będzie dotyczył tej wersji, którą teraz masz.


0
2017-12-08 16:21





Cokolwiek jest zawarte w instrukcji użycia, będzie miało to IDispoable.Dispose zwany jako podyktowany przez IDisposable berło. Jak widać w witrynie MSDN dla using...

Zapewnia wygodną składnię, która   zapewnia poprawne użycie IDisposable   obiekty.

Dlatego jeśli umieścisz niestandardowy typ w using oświadczenie, że powinno odpowiednio oczyszczać swoje zasoby za pośrednictwem IDisposable berło.


0
2017-12-08 16:22





Dzięki temu, że twoja klasa implementuje IDisposable, metoda dispose jest wywoływana tylko przy użyciu instrukcji "using". W przeciwnym razie musisz jawnie wywołać dispose.

Zazwyczaj IDisposable jest implementowany przez obiekty, które zarządzają zużyciem pamięci poza śmieciarem (np. Przy użyciu kodu niezarządzanego na przykład). Zapewnia sposób na wyczyszczenie dowolnej zużytej pamięci.

Dopóki twoja klasa NetworkAccess implementuje IDisposable, metoda dispose zostanie wywołana zaraz po zakończeniu zakresu instrukcji using. Jeśli jest to kod zarządzany, nie musisz go usuwać. Po prostu niech zbieracz śmieci wykona swoją pracę.


0
2017-12-08 16:24





Użyj własnego bloku try / finally, który wykonuje podobną logikę do "używania", ale tylko zadaje, jeśli ustawiono useNetworkAccess. Zauważ, że jeśli na useNetworkAccess mogą mieć wpływ inne wątki, powinieneś skopiować jego wartość i użyć tej kopii zarówno do utworzenia zasobu, jak i do jego usunięcia.


0
2017-12-08 16:41