These aren't really .NET specific, but more general design:
One that immediately springs to mind (because I've seen this today and been ranting about it, and seen too many times before) is wrapping code with conditional checks for broken invariants, in order to avoid exceptions.
So, you end up with a system where some feature isn't working and you have no idea why this is the case, and have zero information on the original cause.
A great example I saw this week was one of our engineers had null reference checks around member variables which the UI framework (WPF) was responsible for assigning. These checks then avoided performing operations which would result in a null ref exception. So, in the event of this (catastrophic error) we have disabled functionality, a confused user and a pissed of support team.
So, fail fast, fail obviously (if possible) and record as much information as possible.
Another one of my favorite guiding principles is to minimize mutability. Where possible I prefer to design immutable classes. Immutability is becoming more fashionable now because of the multicore issue and the need to design for concurrency. I started using it though quite a while back having needed to simplify a system with complex graphs of shared state. I modelled the system on similar ideas to .NET's String and StringBuilder (it's sometimes handy to have a builder class to build up an immutable object particularly if it's fairly complex).
This was in fact my second version of this particular component. What I found was that designing to minimize mutability, and implementing immutable classes massively simplified the code base.
I've found that very few engineers consider this factor even when designing concurrent systems, and often end up with masses of extremely complex fragile code. I'm usually impressed in a way that they can get it to work! But, personally to me really good code should look simple.
Regards,
Phil