Wszyscy inni już napisali, jaki powinien być prawidłowy projekt twojej klasy , więc tego nie powtórzę. Jednak nie widziałem żadnego wyjaśnienia, dlaczego to, co chcesz, nie jest możliwe. Więc oto idzie.
To, co chcesz zrobić, to wykryć podczas wywołania Dispose
, że ta metoda jest wywoływana w kontekście wyjątku. Gdy będziesz w stanie to zrobić, programiści nie będą musieli jawnie dzwonić pod numer Commit
. Jednak problem polega na tym, że nie ma możliwości niezawodnego wykrycia tego w .NET. Podczas gdy istnieją mechanizmy sprawdzające ostatni zgłoszony błąd (np. HttpServerUtility.GetLastError), mechanizmy te są specyficzne dla hosta (w związku z tym ASP.NET ma inny mechanizm, na przykład jako formularze systemu Windows). I chociaż można napisać implementację dla konkretnej implementacji hosta, na przykład implementację, która działałaby tylko w środowisku ASP.NET, jest jeszcze jeden ważniejszy problem: co, jeśli twoja klasa Database
jest używana lub tworzona w kontekście wyjątku ? Oto przykład:
try
{
// do something that might fail
}
catch (Exception ex)
{
using (var database = new Database())
{
// Log the exception to the database
database.Add(ex);
}
}
Gdy klasa Database
jest używany w kontekście Exception
, jak w powyższym przykładzie, jaki jest Twój sposób Dispose
wiedzieć, że nadal musi popełnić? Mogę wymyślić sposoby obejścia tego, ale będzie to dość kruche i podatne na błędy. Dać przykład.
Podczas tworzenia pliku Database
można sprawdzić, czy jest on wywoływany w kontekście wyjątku, a jeśli tak jest, zapisz ten wyjątek. W czasie wywołania Dispose
sprawdza się, czy ostatni zgłoszony wyjątek różni się od wyjątku zapisanego w pamięci podręcznej. Jeśli to się zmieni, powinieneś wycofać. Jeśli nie, zatwierdz.
Chociaż wydaje się to dobrym rozwiązaniem, co z tym przykładem kodu?
var logger = new Database();
try
{
// do something that might fail
}
catch (Exception ex)
{
logger.Add(ex);
logger.Dispose();
}
W tym przykładzie widać, że instancja Database
jest tworzony przed blokiem try. Dlatego nie może poprawnie wykryć, że nie może wycofać. Chociaż może to być przykładowy przykład, pokazuje trudności, które napotkasz, próbując zaprojektować swoją klasę w sposób, w jaki nie jest potrzebne żadne wyraźne wywołanie do Commit
.
W końcu utworzysz klasę Database
trudną do zaprojektowania, trudną w utrzymaniu i nigdy nie naprawisz.
jak wszyscy inni już wspomniano, projekt, który wymaga wyraźnej Commit
lub Complete
połączenia, byłoby łatwiejsze do wdrożenia, łatwiej uzyskać prawo, łatwiejsze w utrzymaniu i daje kod użytkowania, który jest bardziej czytelny (na przykład dlatego, że wygląda na to, czego oczekują deweloperzy).
Ostatnia uwaga, jeśli martwisz się o deweloperzy zapominając wywołać tę metodę Commit
: można zrobić kilka kontroli w metodzie Dispose
aby sprawdzić, czy jest ona wywołana bez Commit
nazywa i pisać do konsoli lub ustawić punkt przerwania podczas debugowanie. Kodowanie takiego rozwiązania byłoby jeszcze łatwiejsze niż próba pozbycia się w ogóle.
Aktualizacja: Adrian wrote interesującą alternatywą dla korzystania HttpServerUtility.GetLastError. Jak zauważa Adrian, możesz użyć Marshal.GetExceptionPointers()
, który jest ogólnym sposobem, który działa na większości hostów. Należy zauważyć, że to rozwiązanie ma te same wady, które wyjaśniono powyżej i że wywoływanie klasy Marshal
jest możliwe tylko w pełnym zaufaniu.
Adrian, masz to, nie chcę trenować o użyciu wzoru, tylko rozwiązanie techniczne, działało pięknie. –
Proszę spojrzeć na moją odpowiedź. Próbuję wyjaśnić, dlaczego sprawdzanie wyjątków w metodzie "Dispose" jest złym pomysłem. – Steven
@Steven: Jak większość odpowiedzi (w tym Twoja) zgodziła się, nie jest to mądry wzorzec do użycia. Mimo to pierwotne pytanie spytało, czy * możliwe * jest wiedzieć, czy wyjątek został zgłoszony w metodzie "Dispose", co pokazuje moja odpowiedź - nawet jeśli ma ona powiązane problemy. – adrianbanks