Все остальные уже написали, каким должен быть правильный дизайн вашего класса Database
, поэтому я не буду повторять это. Однако я не видел никакого объяснения, почему то, что вы хотите, невозможно. Итак, вот и все.
Во время вызова Dispose
вы хотите обнаружить, что этот метод вызывается в контексте исключения. Когда вы сможете сделать это, разработчикам не придется явно вызывать Commit
. Однако проблема здесь в том, что нет способа надежного обнаружения этого в .NET. Хотя существуют механизмы для запроса последней выданной ошибки (например, HttpServerUtility.GetLastError ), эти механизмы зависят от хоста (поэтому ASP.NET имеет другой механизм, например, формы Windows). И хотя вы могли бы написать реализацию для конкретной реализации хоста, например, реализацию, которая будет работать только в ASP.NET, есть еще одна более важная проблема: что, если ваш класс Database
используется или создается внутри контекст исключения? Вот пример:
try
{
// do something that might fail
}
catch (Exception ex)
{
using (var database = new Database())
{
// Log the exception to the database
database.Add(ex);
}
}
Когда ваш класс Database
используется в контексте Exception
, как в примере выше, как ваш метод Dispose
должен знать, что он все еще должен фиксироваться? Я могу придумать способы обойти это, но это будет довольно хрупким и подверженным ошибкам Чтобы привести пример.
Во время создания Database
вы можете проверить, вызывается ли он в контексте исключения, и, если это так, сохранить это исключение. Во время вызова Dispose
вы проверяете, отличается ли последнее выброшенное исключение от кэшированного исключения. Если это отличается, вы должны откат. Если нет, передайте.
Хотя это кажется хорошим решением, как насчет этого примера кода?
var logger = new Database();
try
{
// do something that might fail
}
catch (Exception ex)
{
logger.Add(ex);
logger.Dispose();
}
В примере вы видите, что экземпляр Database
создается перед блоком try. Поэтому он не может правильно определить, что он не может откатиться. Хотя это может быть надуманным примером, он показывает трудности, с которыми вы столкнетесь при попытке создать свой класс таким образом, чтобы не требовался явный вызов Commit
.
В конце концов, вы сделаете свой класс Database
трудным для разработки, сложным в обслуживании, и вы никогда не сделаете это правильно.
Как уже говорили другие, дизайн, который требует явного вызова Commit
или Complete
, будет проще в реализации, легче понять, проще в обслуживании и даст код использования, который будет более читабельным (например, , потому что это выглядит так, как ожидают разработчики).
Последнее замечание, если вы беспокоитесь о том, что разработчики забыли вызвать этот метод Commit
: вы можете выполнить некоторую проверку в методе Dispose
, чтобы увидеть, вызывается ли он без Commit
, и записать в консоль. или установите точку останова во время отладки. Кодировать такое решение было бы намного проще, чем пытаться вообще избавиться от Commit
.
Обновление:
Адриан написал интересную альтернативу использованию HttpServerUtility.GetLastError. Как отмечает Адриан, вы можете использовать Marshal.GetExceptionPointers()
, который является общим способом, который будет работать на большинстве хостов. Обратите внимание, что это решение имеет те же недостатки, которые описаны выше, и что вызов класса Marshal
возможен только при полном доверии