Edytuj: Dwie opcje przedstawione poniżej.Jaki jest najlepszy sposób na odzyskanie skonstruowanych IDisposables bezpiecznie?
Jeśli jesteś tylko przy użyciu funkcjonalności, którą zapewnia IDisposable, trafnie nazwana klauzula using
działa dobrze. Jeśli w obiekcie znajduje się opakowanie an IDisposable
, sam obiekt zawierający musi być IDisposable
i trzeba zaimplementować odpowiedni wzorzec (albo zapieczętowaną klasę IDisposable
, albo program Messier, ale standard virtual
pattern).
Ale czasami metoda fabryki pomocniczej jest dobra dla czystości. Jeśli zwrócisz IDisposable
bezpośrednio po zakończeniu budowy, wszystko jest w porządku, ale jeśli najpierw je skonstruujesz, a następnie zmodyfikujesz lub w inny sposób wykonasz kod, który może wyrzucić wyjątek przed powrotem, musisz bezpiecznie zadzwonić pod numer .Dispose()
- ale tylko, jeśli był błąd.
Na przykład, kod niebezpieczne może wyglądać tak ...
DbCommand CreateCommandUnsafely(string commandText)
{
var newCommand = connection.CreateCommand();
newCommand.CommandText = commandText; //what if this throws?
return newCommand;
}
Solutions Dwa bezpieczne warianty następująco ...
DbCommand CreateCommandSafelyA(string commandText)
{
DbCommand newCommand = null;
bool success = false;
try {
newCommand = connection.CreateCommand();
newCommand.CommandText = commandText; //if this throws...
success=true;
return newCommand;
} finally{
if (!success && newCommand != null)
newCommand.Dispose(); //...we'll clean up here.
}
}
DbCommand CreateCommandSafelyB(string commandText)
{
DbCommand newCommand = null;
try {
newCommand = connection.CreateCommand();
newCommand.CommandText = commandText; //if this throws...
return newCommand;
} catch {
if (newCommand != null)
newCommand.Dispose(); //...we'll clean up here.
throw;
}
}
Bezpieczne Wariant A jest już tylko jedna linia , ale wydaje się, że jest to podejście idiomatyczne. Nie wydaje się, aby istniały jakieś naprawdę zwięzłe rozwiązania, chociaż niektóre z poniższych plakatów podają niektóre opcje wykorzystujące lambdę, które wyodrębniają enkapsulację tej logiki.
Bloat kod z którymś z bezpiecznych metod pozostaje i jest szczególnie obciążające z kodem, który początkowo wyglądał jak ...
return new MyDisposableThing {
OptionA = "X",
OptionB = B.Blabla,
Values = src.Values.Where(priority => priority > 1.0),
};
Powyższy kod pobiera napisany bezpiecznie jest trochę dłuższy i mniej czytelny ponieważ nie można już bezpiecznie używać skróconej składni ustawiającej.
To wygląda jak kod, który widzę gdzie indziej. Czy wiesz, dlaczego jest to lepsze? –
Łapanie arbitralnych wyjątków (jak to sugerują inne odpowiedzi) powoduje różnorodność problemów w szczególnych okolicznościach i powinno się ich unikać, gdy tylko jest to możliwe. Poprzez umieszczenie utylizacji wewnątrz instrukcji 'finally', standardowy wzorzec unika wychwytywania wyjątków i (gdy tworzenie obiektu się nie powiedzie) naśladuje zachowanie nominalnej instrukcji' using'. –