| Preface | p. xi |
| CLR/Framework Gotchas | p. 1 |
| Type alias size doesn't match what you're familiar with | p. 1 |
| struct and class differ in behavior | p. 4 |
| Returning value types from a method/property is risky | p. 9 |
| You can't force calls to your value-type constructors | p. 12 |
| String concatenation is expensive | p. 15 |
| Exceptions may go unhandled | p. 18 |
| Uninitialized event handlers aren't treated gracefully | p. 25 |
| Division operation isn't consistent between types | p. 30 |
| Typeless ArrayList isn't type-safe | p. 34 |
| Type.GetType() may not locate all types | p. 39 |
| Public key reported by sn.exe is inconsistent | p. 44 |
| Visual Studio and Compiler Gotchas | p. 46 |
| Compiler warnings may not be benign | p. 46 |
| Ordering of catch processing isn't consist across languages | p. 54 |
| Type.GetType() might fail at run-time | p. 58 |
| rethrow isn't consistent | p. 60 |
| Default of Option Strict (off) isn't good | p. 65 |
| Versioning may lead to Serialization headaches | p. 70 |
| Creating Web apps can be painful | p. 83 |
| Naming XML documentation for IntelliSense support isn't intuitive | p. 87 |
| Language and API Gotchas | p. 89 |
| Singleton isn't guaranteed process-wide | p. 89 |
| Default performance of Data. ReadXML is poor | p. 93 |
| enum lacks type-safety | p. 97 |
| Copy Constructor hampers exensibility | p. 102 |
| Clone() has limitations | p. 110 |
| Access to static/Shared members isn't enforced consistently | p. 121 |
| Details of exception may be hidden | p. 124 |
| Object initialization sequence isn't consistent | p. 129 |
| Polymorphism kicks in prematurely | p. 133 |
| Unit testing private methods is tricky | p. 138 |
| Language Interoperability Gotchas | p. 146 |
| Common Language Specification Compliance isn't the default | p. 146 |
| Optional parameters break interoperability | p. 148 |
| Mixing case between class members breaks interoperability | p. 151 |
| Name collision with keywords breaks interoperability | p. 153 |
| Defining an array isn't consistent | p. 156 |
| Garbage Collection Gotchas | p. 160 |
| Writing Finalize() is rarely a good idea | p. 161 |
| Releasing managed resources in Finalize() can wreak havoc | p. 164 |
| Rules to invoke base.Finalize() aren't consistent | p. 171 |
| Depending on Finalize() can tie up critical resources | p. 173 |
| Using Finalize() on disposed objects is costly | p. 177 |
| Implementing IDisposable isn't enough | p. 180 |
| Using the Dispose Design Pattern doesn't guarantee cleanup | p. 189 |
| Inheritance and Polymorphism Gotchas | p. 192 |
| Runtime Type Identification can hurt extensibility | p. 192 |
| Using new/shadows causes "hideous hiding" | p. 202 |
| Compilers are lenient toward forgotten override/overrides | p. 205 |
| Compilers lean toward hiding virtual methods | p. 209 |
| Exception handling can break polymorphism | p. 211 |
| Signature mismatches can lead to method hiding | p. 218 |
| Multithreading Gotchas | p. 223 |
| The Thread class supports some dangerous methods/properties | p. 223 |
| Foreground threads may prevent a program from terminating | p. 224 |
| Background threads don't terminate gracefully | p. 227 |
| Interrupt () kicks in only when a thread is blocked | p. 229 |
| ThreadAbortException-a hot potato | p. 232 |
| Environment.Exit() brings down the CLR | p. 235 |
| ResetAbort() may lead to surprises | p. 238 |
| Abort() takes time to clean up | p. 240 |
| Calling Type.GetType() may not return what you expect | p. 243 |
| Locking on globally visible objects is too sweeping | p. 250 |
| Threads from the thread pool are scarce | p. 256 |
| Threads invoked using delegates behave like background threads | p. 260 |
| Passing parameters to threads is tricky | p. 263 |
| Exceptions thrown from threads in the pool are lost | p. 274 |
| Accessing WinForm controls from arbitrary threads is dangerous | p. 284 |
| Web-service proxy may fail when used for multiple asynchronous calls | p. 293 |
| Raising events lacks thread-safety | p. 299 |
| COM-Interop and Enterprise Services Gotchas | p. 307 |
| Release of COM object is confusing | p. 307 |
| Using interface pointers after calling ReleaseComObject() will fail | p. 311 |
| Cross-apartment calls are expensive | p. 313 |
| Default apartment of main thread is inconsistent across languages | p. 318 |
| STAThread attribute may have no effect on your methods | p. 321 |
| Spattering access to COM components makes code hard to maintain | p. 325 |
| Auto-generating GUID for your classes leads to versioning woes | p. 327 |
| All but one of the ClassInterface options are ineffective | p. 332 |
| Simply turning the switch for COM interop is dangerous | p. 337 |
| ServicedComponents implemented inconsistently on XP and 2003 | p. 339 |
| AutoComplete comes with undesirable side effects | p. 351 |
| Appendix | p. 357 |
| Index | p. 363 |
| Table of Contents provided by Ingram. All Rights Reserved. |