Introduction xi
Chapter 1: Working with Data Types 1
Item 1: Use Properties Instead of Accessible Data Members 1
Item 2: Prefer Implicit Properties for Mutable Data 8
Item 3: Prefer Immutability for Value Types 12
Item 4: Distinguish Between Value Types and Reference Types 18
Item 5: Ensure That 0 Is a Valid State for Value Types 24
Item 6: Ensure That Properties Behave Like Data 28
Item 7: Limit Type Scope by Using Tuples 34
Item 8: Define Local Functions on Anonymous Types 39
Item 9: Understand the Relationships Among the Many Different Concepts of Equality 45
Item 10: Understand the Pitfalls of GetHashCode() 54
Chapter 2: API Design 61
Item 11: Avoid Conversion Operators in Your APIs 61
Item 12: Use Optional Parameters to Minimize Method Overloads 65
Item 13: Limit Visibility of Your Types 69
Item 14: Prefer Defining and Implementing Interfaces to Inheritance 73
Item 15: Understand How Interface Methods Differ from Virtual Methods 82
Item 16: Implement the Event Pattern for Notifications 86
Item 17: Avoid Returning References to Internal Class Objects 93
Item 18: Prefer Overrides to Event Handlers 97
Item 19: Avoid Overloading Methods Defined in Base Classes 100
Item 20: Understand How Events Increase Runtime Coupling Among Objects 104
Item 21: Declare Only Nonvirtual Events 107
Item 22: Create Method Groups That Are Clear, Minimal, and Complete 113
Item 23: Give Partial Classes Partial Methods for Constructors, Mutators, and Event Handlers 120
Item 24: Avoid ICloneable Because It Limits Your Design Choices 125
Item 25: Limit Array Parameters to params Arrays 129
Item 26: Enable Immediate Error Reporting in Iterators and Async Methods Using Local Functions 134
Chapter 3: Task-Based Asynchronous Programming 139
Item 27: Use Async Methods for Async Work 139
Item 28: Never Write async void Methods 143
Item 29: Avoid Composing Synchronous and Asynchronous Methods 149
Item 30: Use Async Methods to Avoid Thread Allocations and Context Switches 154
Item 31: Avoid Marshalling Context Unnecessarily 156
Item 32: Compose Asynchronous Work Using Task Objects 160
Item 33: Consider Implementing the Task Cancellation Protocol 166
Item 34: Cache Generalized Async Return Types 173
Chapter 4: Parallel Processing 177
Item 35: Learn How PLINQ Implements Parallel Algorithms 177
Item 36: Construct Parallel Algorithms with Exceptions in Mind 189
Item 37: Use the Thread Pool Instead of Creating Threads 195
Item 38: Use BackgroundWorker for Cross-Thread Communication 201
Item 39: Understand Cross-Thread Calls in XAML Environments 205
Item 40: Use lock() as Your First Choice for Synchronization 214
Item 41: Use the Smallest Possible Scope for Lock Handles 221
Item 42: Avoid Calling Unknown Code in Locked Sections 225
Chapter 5: Dynamic Programming 229
Item 43: Understand the Pros and Cons of Dynamic Typing 229
Item 44: Use Dynamic Typing to Leverage the Runtime Type of Generic Type Parameters 238
Item 45: Use DynamicObject or IDynamicMetaObjectProvider for Data-Driven Dynamic Types 242
Item 46: Understand How to Use the Expression API 253
Item 47: Minimize Dynamic Objects in Public APIs 259
Chapter 6: Participate in the Global C# Community 267
Item 48: Seek the Best Answer, Not the Most Popular Answer 267
Item 49: Participate in Specs and Code 269
Item 50: Consider Automating Practices with Analyzers 271
Index 273