In this simple example you might be able to get away without throwing an exception. The reason is that, as described, this particular problem is one where all the checks occur first, and then if they pass the data is changed.
So the object could be constructed with extra property(ies) that can be set to indicate whether the delete operation occurred and if not, why not.
But in the more general case this won't really work, because the checking logic and database update logic get intermixed (at least across different objects). In that case you need the transaction to roll back, and that is triggered by throwing an exception - which is the standard .NET technique for triggering such a rollback.
Even then, if you really wanted to, you could devise your own infrastructure to indicate the need for a rollback and manually handle your transactions. Keeping in mind, of course, that a grandchild object deep in the object graph could trigger the rollback requirement, so your infrastructure would need to flag this case - and all your other could would need to constantly check it to break out of any loops and stop processing and roll back the transaction.
In short, there's a reason .NET favors the use of exceptions for this problem - because inventing your own out-of-band notification scheme would be a lot of work, and would almost certainly complicate the heck out of your code.
Copyright (c) Marimer LLC