Design by Contract is best demonstrated in Eifel.
Basically if it's well integrated you do all your assertions outside of the function.
Every interface is a Contract per definition but one of the main issues are runtime errors those are mostly a consequence of side-effects.
If we got IO we won't get rid of side-effects.
So the question of error propagation arises. Do I want the application fail inside of the method? or before?
a contract by design is basically a membrane before your runtime error to predict runtime errors in a better way.
I personally love Design by Contract, it's like TDD it helps you write better code.
not only because of the tests but also because it makes you approach code differently without cluttering your core functionality.
I don't want an if condition that asserts the input A is bigger than 12 and smaller than 24 inside of my method.
It distracts me from what actually should happen.
I actually implemented my own library (not C#) for these things but still the error will happen inside of the method.
Which is actually something we don't want, but more along the line of Functional programming as a wrapper around our method.
F(x) -> b
would become something along the line
C(x) -> F(x) -> b | E(x)
to speak OOP ... a Contractual Decorator so to say
I would never do something religiously, I was member of to many religions to take them seriously.
It's a cool way of extracting conditions and keep code more readable.
As one classic hint esp in combination with TDD CbD is strict on what comes in but loose on what goes out.
If done right, it allows you to separate most preconditions as well as most of post conditions out of your code.
that is less noise inside of your code -> less noise is always better.
But try it for yourself ... not everyone has to become a fanboy. I would recommend building your own opinion and try to weigh if it makes sense for you.
don't become a 'i got a hammer, everything's a nail now'-developer.