How to code .NET

231 810 0
How to code .NET

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

How to code .NET

CYAN MAGENTA YELLOW BLACK PANTONE 123 CV BOOKS FOR PROFESSIONALS BY PROFESSIONALS ® Author of Ajax Patterns and Best Practices Foundations of ObjectOriented Programming Using NET 2.0 Patterns Dear Reader, Like you, I am a coder, architect, and developer People who are coders, architects, or developers strive to their best, and if given the choice they will always something correctly Of course, this begs the question: Why we have so many bugs in our code? I think the main reason for buggy code is that we are all short on time We don’t have the luxury of investigating new Framework features fully or exploring innovative new techniques as thoroughly as we would like, because we’re all watching the clock That means our code has bugs—the new Framework feature we implemented doesn’t work quite as expected, and the new best practice we put in place doesn’t seem to work the same way for every input These bugs are frustrating and can often be very difficult to solve This book is a response to that problem In it I have investigated and recorded my experiences of a wide range of NET Framework features They’re arranged in simple, bite-sized sections dedicated to problem solving, informing you of little-known functionality and keeping you up to date with the latest design thinking It’s a road map to your more effective use of the NET Framework For example, the NET Framework 2.0 introduced the yield keyword On the face of it, this is a really cool new piece of functionality that we’d all like to use But what’s it really like? Is it buggy? Is it going to be the future of all iterators? This book digs into these questions and more to provide you with the answers that you need Christian Gross Companion eBook Available How to Code NET Ajax and REST Recipes: A Problem-Solution Approach How to Code NET: Tips and Tricks for Coding NET 1.1 and NET 2.0 Applications Effectively THE EXPERT’S VOICE ® IN NET How to Code NET Tips and Tricks for Coding NET 1.1 and NET 2.0 Applications Effectively Join online discussions: Companion eBook forums.apress.com SOURCE CODE ONLINE FOR PROFESSIONALS BY PROFESSIONALS ™ www.apress.com See last page for details on $10 eBook version ISBN 1-59059-744-3 Shelve in NET 89253 59744 Gross 90000 Christian Gross 781590 597446 User level: Beginner–Intermediate this print for content only—size & color not accurate 7" x 9-1/4" / CASEBOUND / MALLOY 7443FM.qxd 9/21/06 10:46 PM Page i How to Code NET Tips and Tricks for Coding NET 1.1 and NET 2.0 Applications Effectively Christian Gross 7443FM.qxd 9/21/06 10:46 PM Page ii How to Code NET: Tips and Tricks for Coding NET 1.1 and NET 2.0 Applications Effectively Copyright © 2006 by Christian Gross All rights reserved No part of this work may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording, or by any information storage or retrieval system, without the prior written permission of the copyright owner and the publisher ISBN-13 (pbk): 978-1-59059-744-6 ISBN-10 (pbk): 1-59059-744-3 Printed and bound in the United States of America Trademarked names may appear in this book Rather than use a trademark symbol with every occurrence of a trademarked name, we use the names only in an editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the trademark Lead Editor: Ewan Buckingham Technical Reviewer: Jason Lefebvre Editorial Board: Steve Anglin, Ewan Buckingham, Gary Cornell, Jason Gilmore, Jonathan Gennick, Jonathan Hassell, James Huddleston, Chris Mills, Matthew Moodie, Dominic Shakeshaft, Jim Sumser, Keir Thomas, Matt Wade Project Manager: Richard Dal Porto Copy Edit Manager: Nicole Flores Copy Editors: Candace English, Nicole Abramowitz Assistant Production Director: Kari Brooks-Copony Production Editor: Kelly Gunther Compositor: Gina Rexrode Proofreader: Linda Seifert Indexer: Michael Brinkman Artist: April Milne Cover Designer: Kurt Krames Manufacturing Director: Tom Debolski Distributed to the book trade worldwide by Springer-Verlag New York, Inc., 233 Spring Street, 6th Floor, New York, NY 10013 Phone 1-800-SPRINGER, fax 201-348-4505, e-mail orders-ny@springer-sbm.com, or visit http://www.springeronline.com For information on translations, please contact Apress directly at 2560 Ninth Street, Suite 219, Berkeley, CA 94710 Phone 510-549-5930, fax 510-549-5939, e-mail info@apress.com, or visit http://www.apress.com The information in this book is distributed on an “as is” basis, without warranty Although every precaution has been taken in the preparation of this work, neither the author(s) nor Apress shall have any liability to any person or entity with respect to any loss or damage caused or alleged to be caused directly or indirectly by the information contained in this work The source code for this book is available to readers at http://www.apress.com in the Source Code/ Download section 7443FM.qxd 9/21/06 10:46 PM Page iii Contents at a Glance About the Author vii About the Technical Reviewer ix Acknowledgments xi Introduction xiii ■ CHAPTER ■ CHAPTER ■ CHAPTER ■ CHAPTER Testing Your Code NET Runtime- and Framework-Related Solutions 31 Text-Related Solutions 85 C# Coding Solutions 117 ■ INDEX 209 iii 7443FM.qxd 9/21/06 10:46 PM Page iv 7443FM.qxd 9/21/06 10:46 PM Page v Contents About the Author vii About the Technical Reviewer ix Acknowledgments xi Introduction xiii ■ CHAPTER Testing Your Code Quick Notes About TDD Getting Started with TDD and NUnit Writing Tests Using Contexts and Results Writing Tests for Code Pieces That Have No Tests or Few Tests 11 Writing Tests for Code Pieces That Don’t Give Information Back 19 Verifying the Correctness of an Object Instance Without Having Access 26 ■ CHAPTER NET Runtime- and Framework-Related Solutions 31 Keeping Value Types and Reference Types Straight 31 Using Delegates 41 Versioning Assemblies 43 Loading and Unloading Assemblies Dynamically 47 Loading Assemblies Dynamically 47 Loading and Unloading Assemblies Dynamically 52 Implementing GetHashCode 67 Thinking of NET Generics as Black Boxes 72 Figuring Out What Generic Methods Do 76 Using the new and class Keywords with NET Generics 82 ■ CHAPTER Text-Related Solutions 85 Converting a String to an Array and Vice Versa 85 Parsing Numbers from Buffers 89 Processing Plain-Vanilla Numbers in Different Cultures 89 Managing the Culture Information 93 v 7443FM.qxd vi 9/21/06 10:46 PM Page vi ■CONTENTS When to Use StringBuilder 97 Finding a Piece of Text Within a Text Buffer 101 Always Implement ToString 104 Using a Disposable Type to Find Multiple Text Pieces and Iterate the Results 106 Making ToString Generate Structured Output 110 ■ CHAPTER C# Coding Solutions 117 What Does the Yield Keyword Really Generate? 117 Using Inheritance Effectively 123 Implementing Interfaces 128 Naming Conventions for a Namespace, a Class, and an Interface 135 Namespaces 135 Class and Interface Identifiers 136 Understanding the Overloaded Return Type and Property 139 Nullable Types: A Null Is Not Always a Null 145 Abstract-Class Bridge-Pattern Variation 148 Nested Private-Class Bridge-Pattern Variation 151 Dealing with Marker Interfaces or Base Classes 153 Editing Text Using the Command Pattern 154 Marker Interfaces and Their Dependencies 156 How Marker Interfaces Dependencies Are Implemented 157 A Null Value Is Not Always a Null State 165 The Essentials of the Factory Pattern 169 The Classical Factory Pattern 170 More Sophisticated Factory Implementations 173 Don’t Expose a Class’s Internal State 178 Designing Consistent Classes 181 Immutable Types Are Scalable Types 187 Understanding and Using Functors 191 The Comparer Functor 196 The Closure Functor 200 The Predicate Functor 200 The Transformer Functor 202 Functors in Practice 202 Avoiding Parameters That Have No Identity 205 ■ INDEX 209 7443FM.qxd 9/21/06 10:46 PM Page vii About the Author Many people say that by looking at a person’s dog, you can tell what the person is like Well, the picture of me is my dog Louys, an English Bulldog And yes, my English Bulldog and I have many common characteristics But what about my biography? It’s pretty simple: I am guy who has spent oodles of time strapped to a chair debugging and taking apart code In fact, I really enjoy this business we call software development I have ever since I learned how to peek and poke my first bytes I have written various books, including Ajax and REST Recipes: A Problem-Solution Approach, Foundations of ObjectOriented Programming Using NET 2.0 Patterns, and A Programmer’s Introduction to Windows DNA, all available from Apress These days I enjoy coding and experimenting with NET, as it is a fascinating environment .NET makes me feel like a kid opening a present on Christmas morning You had an idea what the gift was, but you were not completely sure And with NET there is no relative giving you socks or a sweater It’s excitement all the way! vii 7443FM.qxd 9/21/06 10:46 PM Page viii 7443FM.qxd 9/21/06 10:46 PM Page ix About the Technical Reviewer ■JASON LEFEBVRE is vice president and founding partner of Intensity Software, Inc (http://www.intensitysoftware.com), which specializes in providing custom Microsoft NET applications, IT consulting services, legacy system migration, and boxed software products to a rapidly growing set of clients Jason has been using Microsoft NET since its Alpha stages in early 2000 and uses Visual Studio and the Microsoft NET Framework daily while creating solutions for Intensity Software’s clients Jason has been a participating author for a number of books and has written numerous articles about Microsoft NET-related topics ix 7443CH04.qxd 202 9/17/06 1:37 PM Page 202 CHAPTER ■ C# CODING SOLUTIONS The Transformer Functor Another type of functor is the Transformer functor It takes one type as a parameter and uses a mapping to return some equivalent of the original type to a new type The big picture idea behind a Transformer functor is to make it possible for a user to continue using one type that will be converted dynamically into another type For instance, the Transformer functor is useful in the context of integrating a new system with legacy objects, or vice versa The following is the delegate definition of the Transformer functor: Source: /Volume01/LibVolume01/UnderstandingUsingFunctors.cs public delegate outType DelegateTransformer(inpType input); The delegate DelegateTransformer is a NET Generics type with two parameters, where the type inpType is the input, and the type outType is the output that the input is converted into Functors in Practice Functors are easy to explain, and providing a reason for using them is not difficult What is more difficult is actually using them Using them can be awkward because of the separation of functionality between the functor and the type being managed I will use a movie-ticket application to illustrate the details of using a functor, interface, and implementation as a single solution The heart of the ticketing system is Ticket, which represents a movie ticket and is defined as follows: Source: /Volume01/LibVolume01/UnderstandingUsingFunctors.cs public class Ticket { private double _price; private int _age; public Ticket( double price, int age) { _price = price; _age = age; } public virtual get { return } } public virtual get { return } } } double Price { _price; int Age { _age; 7443CH04.qxd 9/17/06 1:37 PM Page 203 CHAPTER ■ C# CODING SOLUTIONS Ticket has only two data members, _age and _price, which represent the age of the moviegoer and the price of the ticket The age and price are defined when Ticket is instantiated The properties Age and Price retrieve the values of age and price, respectively When selling movie tickets, ticket sales is an important statistic Ticket sales indicate the popularity and success of a movie In a traditional programming approach ticket sales are calculated by iterating a collection of Tickets The total would be counted each time a ticket sales total is asked for Another approach would be to use a closure functor The following source code calculates the total sales for a movie using a closure functor: Source: /Volume01/LibVolume01/UnderstandingUsingFunctors.cs public class TicketsBuilder { private class StatisticsCounter { private double _runningTotal; public StatisticsCounter() { _runningTotal = 0.0; } public void ClosureMethod( Ticket ticket) { _runningTotal += ticket.Price; } } public static IList CreateCollection() { return new ClosureAddProxy< Ticket>( new List< Ticket>(), new DelegateClosure< Ticket>( new StatisticsCounter().ClosureMethod)); } } TicketsBuilder is a class that has a method, CreateCollection, that creates an IList instance The method CreateCollection instantiates the type ClosureAddProxy, which implements the Proxy pattern for the closure functor The parent collection for ClosureAddProxy is List The delegate used for the closure functor is StatisticsCounter.ClosureMethod Like in the comparer functor example, every time an element is added to the returned IList instance DelegateAddClosure will call the closure delegate Each time the closure delegate StatisticsCounter.ClosureMethod method is called, the input price is added to the total ticket sales The class StatisticsCounter.ClosureMethod is not entirely accurate, however Imagine that a person buys a ticket and then asks for her money back or decides to watch a different movie The ticket would need to be removed from the collection, and the total sales variable _runningTotal would need to be decremented by the price of the removed ticket Even if it is impossible to get your money back, it is not possible to use such logic for all applications The problem of the corrupted data needs be solved Ticket sales can only be incremented because ClosureAddProxy overrides the methods that add elements to the collection The solution is to use a closure delegate that overrides the remove-element methods The following is an example of two closure functors implementing the add-element and remove-element methods: 203 7443CH04.qxd 204 9/17/06 1:37 PM Page 204 CHAPTER ■ C# CODING SOLUTIONS Source: /Volume01/LibVolume01/UnderstandingUsingFunctors.cs public class TicketsBuilder { private class StatisticsCounter { private double _runningTotal; public StatisticsCounter() { _runningTotal = 0.0; } public void ClosureAddMethod( Ticket ticket) { _runningTotal += ticket.Price; } public void ClosureRemoveMethod( Ticket ticket) { _runningTotal -= ticket.Price; } } public static IList CreateCollection() { StatisticsCounter cls = new StatisticsCounter(); IList parent = new ClosureAddProxy< Ticket>( new List< Ticket>(), new DelegateClosure< Ticket>( cls.ClosureAddMethod)); return new ClosureRemoveProxy( parent, new DelegateClosure< Ticket>( cls.ClosureRemoveMethod)); } } In the modified implementation of TicketsBuilder, StatisticsCounter has two closure methods: ClosureAddMethod and ClosureRemoveMethod The method ClosureAddMethod is used to increment the ticket sales, and the method ClosureRemoveMethod is used to decrement ticket sales The method CreateCollection is modified to create two closure proxies: ClosureAddProxy and ClosureRemoveProxy For each proxy the appropriate closure method is associated The calculation of the grand total for the ticket sales works But there is a very big problem—TicketBuilder creates an instance of StatisticsCounter, but the instance of StatisticsCounter is not saved for reference In other words, statistics are being generated but no client has access to those values The solution for retrieving the total ticket-sales revenue is to create a property called RunningTotal When working with functors, remember the following points: • Using functors does not come naturally because we developers are not wired to write code in such a structure After you’ve written some functors it will feel natural • For most cases there are four types of functors: Comparer, Closure, Predicate, and Transformer • Functors are realized using delegates The functors can be called directly in your source code 7443CH04.qxd 9/17/06 1:37 PM Page 205 CHAPTER ■ C# CODING SOLUTIONS • Often functors are used in conjunction with the Proxy pattern If a Proxy pattern is used, you will need to define interfaces and/or abstract base classes * Functors make it possible to portably use specific application logic in multiple places without having to write special code to call the functors Avoiding Parameters That Have No Identity Writing methods means using parameters, and that means the potential to make the mistake of using parameters that have no identity Of course you shouldn’t avoid writing methods, but be careful Let’s start with a simple problem and provide a well-defined solution The DateTime class is an example of a badly designed constructor that can be easily confusing as to what is a day, month, or year: public DateTime(int year, int month, int day) {} The compiler sees the declaration as public DateTime( int, int, int); If I wrote the following code for December 11, 2002, assuming an American date format, the compiler could not tell me what I did wrong: DateTime date = new DateTime(12, 11, 2); Console.WriteLine( date.ToString()); To make matters worse, the runtime does not even mark this as an error Running the code yields the following result: 11/2/0012 12:00:00 AM The generated format is Canadian formatting and the computer thinks the date is February 11 of the year 12 AD I told you that the generated format is a Canadian date, but can you know that from the formatting? For example, the date could have been a US-formatted November To know the answer, we would have to look at the day, month, and year members of the class The simplest solution to parameters with no identity is to nothing and hope for the best With IDEs like Visual Studio, writing good NET documentation will generate the parameter definitions using IntelliSense It is not always possible to convert the parameters into having an identity If you nothing, then you should convert the NET documentation to generate the appropriate information that the IDEs will pick up A technical solution is to convert the DateTime types into enumerations, as follows: Source: /Volume01/LibVolume01/AvoidingParametersWithoutIdentity.cs enum DayEnumeration : int { } enum MonthEnumeration : int { January = 1, February = 2, 205 7443CH04.qxd 206 9/17/06 1:37 PM Page 206 CHAPTER ■ C# CODING SOLUTIONS March = 3, April = 4, May = 5, June = 6, July = 7, August = 8, September = 9, October = 10, November = 11, December = 12 } enum YearEnumeration : int { } class FixedDateTime { public FixedDateTime( YearEnumeration year, MonthEnumeration month, DayEnumeration day) { } } The source code contains three enumerations: DayEnumeration, MonthEnumeration, and YearEnumeration DayEnumeration and YearEnumerations have no values, and that is OK because none are needed The enumeration definition MonthEnumeration could without defined values as well, but I’ve defined some for convenience The constructor for FixedDateTime uses the three enumerations in the exact same calling sequence as DateTime The difference is that the caller of FixedDateTime would know which field is which The following code illustrates how the developer could have easily caught the error using the enumerations: Source: /Volume01/LibVolume01/UnderstandingUsingFunctors.cs FixedMyDateTime date = new FixedMyDateTime( (YearEnumeration)12, (MonthEnumeration)11, (DayEnumeration)2); As the code is written the int values are typecast from the int value to the enumeration, which can then be typecast back to the int type You may think the typecasts are neither legal nor helpful, but think again It is perfectly legal to declare an enumeration and then use int typecasts When you use the casts you will notice right away which field is the day, month, and year, and in the example there is a problem Using the enumeration to int and back typecast works only for int types In the declaration of the enumeration, the base type of the enumeration was int, and that made the type compatible with the class DateTime Now let’s look at a more complicated problem and a more complicated solution The following source code is an example of a confusing constructor declaration using same types: string message = "message"; string param = "param"; 7443CH04.qxd 9/17/06 1:37 PM Page 207 CHAPTER ■ C# CODING SOLUTIONS ArgumentException exception1 = new ArgumentException( message, param); ArgumentNullException expection2 = new ArgumentNullException( param, message); In the example there are two NET classes: ArgumentException and ArgumentNullException Both classes have a constructor with the same identifiers The difference between the two constructors is the order of the parameters This is confusing and a bad programming practice because there is no consistency in the parameter ordering What makes this an especially bad coding error is that the development environment cannot help you because the compiler sees the following constructor declarations: ArgumentException( string, string); ArgumentNullException( string, string); The compiler sees two declarations that each use two string parameters Fixing the ArgumentException and ArgumentNullException is difficult because the classes expect to see string arguments Using NET it is impossible to convert the string types into another type If you have two buffers of arbitrary content, it is not easy to indicate to the compiler what the buffer’s contents mean There is a solution and that involves wrapping a disposable type on top of the type that you want to improve The following is an example implementation of fixing the ArgumentException using a wrapped disposable type that acts as a factory: Source: /Volume01/LibVolume01/AvoidParametersWithoutIdentity.cs class FixedArgumentException : ArgumentException { string _message; string _paramName; public FixedArgumentException() {} public FixedArgumentException MessageConstructorParameter(string message) { _message = message; return this; } public FixedArgumentException ParamConstructorParameter(string param) { _message = param; return this; } public override string Message { get { return _message; } } public override string ParamName { get { return _paramName; } } 207 7443CH04.qxd 208 9/17/06 1:38 PM Page 208 CHAPTER ■ C# CODING SOLUTIONS public ArgumentException GenerateBaseType() { return new ArgumentException( _message, _paramName); } } In the solution FixedArgumentException subclasses ArgumentException and implements the properties Message and ParamName The idea is to make FixedArgumentException look and feel like an ArgumentException type The FixedArgumentException constructor has no parameters because the parameter values will be defined using the methods MessageConstructorParameter and ParamConstructorParameter Each of the methods returns a reference allowing the methods to be called using a chained mechanism An example of using the explained methods follows: throw new FixedArgumentException() MessageConstructorParameter( "example") ParamConstructorParameter( "no parameter"); In the code the throw and new keywords are used as usual when throwing an exception But referencing of the methods MessageConstructorParameter and ParamConstructorParameter after the type instantiation is a new approach The method calls are being chained together because the methods keep returning the current object instance Using the methods results in a clear definition of the object’s state For situations in which the object cannot be subclassed or made to look and feel like the object, the solution is to add a GenerateBaseType method This would work for the DateTime definition because it is a sealed type definition In the case of the FixedArgumentException, the client code would be modified slightly to the following: throw new FixedArgumentException() MessageConstructorParameter( "example") ParamConstructorParameter( "no parameter") GenerateBaseType(); In the modified code the last method call is GenerateBaseType, and it creates the type The state of the created type depends on the chained methods that are called before calling GenerateBaseType When writing methods and constructors with parameters, remember the following: • Having a parameter signature with multiple identical types can be a problem Be cautious • The simplest solution to multiple identical parameters is to write NET documentation for the API that will be exposed, allowing the development environment to pick up the information for IntelliSense • For int base types, you can use enumerations to distinguish parameters • For all other types, you can use disposal techniques to define constructor parameters • Using disposal techniques when defining constructor parameters can reduce the number of permutations and combinations for defining the state of a type This is especially useful when the constructors are used for immutable objects • The disposal-type techniques work well for reference types, but are less efficient for value types 7443Index.qxd 9/21/06 4:10 PM Page 209 Index A Abstract Class Bridge pattern implementing, 148–151 abstract classes creating instances with Factory pattern, 171–173 using in context of Bridge pattern, 150 abstract keyword, 132–133, 135 Activator class CreateInstance method, 82 Adapter pattern, 151 problem with, 151 Add method Mathematics class, 7, 10 Object class, algorithms naming conventions, 137 AllowParentheses enumeration processing brackets, 92 alpha version, 44 American Standard Code for Information Interchange See ASCII AppDomain class CreateDomain method, 55–56, 59 CreateInstance method, 55 Unload method, 59 Append method HashCodeAutomater class, 69 StringBuilder class, 98–99 Application Object Reference dependency IMarker interface, 156 implementing, 161 Mediator pattern as extension of, 163 AreEqual method Assert class, 7–9 arrays as reference type, 40 converting to strings, 85–89 ASCII (American Standard Code for Information Interchange) description, 86 ASCII property Encoding class, 85–86 assemblies loading plugins, 47 loading and unloading dynamically, 52–67 loading dynamically, 47–52 versioning, 43–47 Assembly class CreateInstance method, 47–48 FullName property, 53 Load method, 47–48 assembly directory resolving identifiers into types and assemblies, 61 assembly redirection example, 46–47 AssemblyFileVersion attribute versioning assemblies, 44 AssemblyLoader class, 51, 53 implementing alternative, 56–57 AssemblyVersion attribute versioning assemblies, 44 Assert class AreEqual method, 7–9 autoboxing, 37 structs value and assigning to reference type, 37–38 B base classes, using, 153–154 bin directory, bottom-up approach compared to top-down, successful working of, 14 box command, 37 Bridge pattern See also Abstract Class Bridge pattern; Nested-Private Class Bridge pattern introduction, 128 brute-force testing, buffers See parsing from numbers to buffers Builder keyword, 137 Builder pattern, 178, 199 implementation, 176 209 7443Index.qxd 210 9/21/06 4:10 PM Page 210 ■INDEX C C# implementing interfaces, 128–135 inheritance, 123–127 naming conventions, 135–139 nullable types, 145–146 yield keyword, 117–123 carryover Generic parameters, 77 catch block catching FormatException class, 90 Chain class, 74 Chain of Command pattern, 153 Chain of Responsibility pattern definition of interfaces, 154 character-translation tables, 87 checked keyword, class keyword using with NET Generics, 82–84 classes as reference types, 31 designing for consistency, 181–187 exposing internal state, 178–180 identifiers, 136–139 testing, 7–11 cloning objects ICloneable interface, 177 Closure functor, 195, 200 ClosureProxy class, 197 Code, benefits of writing simultaneously with tests, code pages, 87 Collection class types naming conventions, 139 collections and Null Object pattern, 169 managing using NET Generics and Object type, 72 UML functor architecture, 196 Command pattern classical definition of interfaces, 153–154 editing text, 154–156 Command-like pattern implementing post NET Generics, 73 implementing pre NET Generics, 72 Comparer functor, 195–200 ComparerProxy class, 197 CompareTo method IComparable interface, 197 CompareValue method fake objects, 23 Compiler keyword, 137 Composite pattern implementing, 148 Concat method String class, 98–99 configuration files resolving identifiers into types and assemblies, 61 Console class WriteLine method, 87, 121–122, 170 Constants type naming conventions, 139 contexts introduction, 6–11 multiplication by context, 15 overflow context, 8–9 simple number context, ControlData class, 75 Convert class testing and converting numbers, 96 Convert method UniversalDataConverter class, 79 CreateDomain method AppDomain class, 55–56, 59 CreateInstance method Activator class, 82 AppDomain class, 55 Assembly class, 47–48 Factory class, 53 CreateObject method Factory class, 172 cross-AppDomain calls, 60 dynamically loading and unloading assemblies solution, 53 culture information managing, 93–96 CultureInfo class, 94 CurrentCulture property Thread class, 93, 96 CurrentThread property Thread class, 93 D data flow Mathematics.Multiply, 19 data types naming conventions, 138 DateTime class Parse method, 95 debugger relying on less as benefit of TDD, Decorator pattern, 130 and Null Object pattern, 169 compared to Proxy pattern, 197 Default identifier, 137 Delegate class GetInvocationList method, 160 Target property, 160 delegate keyword, 137, 193 delegates naming conventions, 137 ramifications of using, 41–43 derived classes See inheritance designing consistent classes, 181–187 7443Index.qxd 9/21/06 4:10 PM Page 211 ■INDEX E Encoding class ASCII property, 85–86 GetBytes method, 85 GetEncoding method, 88 Evidence parameter AppDomain.CurrentDomain, 57 exceptions naming conventions, 136 Execute method ICommand interface, 154 execution in a context part of test, 10 ExpectedException attribute, 10 testing failing contexts, Extensible Stylesheet Language Transformations See XSLT Extension pattern implementing IMarker Object Reference dependency, 158 F Factory class CreateInstance method, 53 CreateObject method, 172 factory delegation resolving identifiers into types and assemblies, 61 Factory pattern, 151 advanced implementations, 173–178 classical implementation, 170–173 failures, analyzing, 17 fake methods, 19 fake objects analyzing output generated by, 17 CompareValue method, 23 introduction, 14 layered approach, 15 reasons for failure to mock, 24 uses, 18 feedback failure problem in Translate method declaration, 20 solution is using mock objects, 21 Finding Text Within Buffer example find all instances of the text, 101 finding all instances of text in buffer, 103 implementing IterateIndice, 109 searching for a single character, 102 searching for array of characters, 102 searching for text from end of buffer, 103 starting search at specific index, 103 string case-insensitive search, 103 using disposable types, 106–108 for loop converting into while loop, 122 foreach statement, 109, 120–121, 123 iterating a collection, 117 FormatException class, 90 FullName property Assembly class, 53 function calls manipulating value and reference types, 31–38, 40–41 functors Closure functor, 200 Comparer functor, 196–200 introduction, 191–195 Predicate functor, 200–201 Transformer functor, 202 using, 202–205 Find it faster at http://superindex.apress.com/ Disposable Type Iterate Text example using anonymous delegates, 108 using yield keyword, 108 disposable types ToString method, 111 using, 106–110 doc directory, DotNetMock objects, 21 DoTranslation class accessing lower-level layers, 23 Translate method, 20–21 dynamically loading and unloading assemblies solution cross-AppDomain calls, 53, 60 implementing alternative AssemblyLoader, 56–58 implementing new assembly loader class, 59 instantiating objects, 59 loading of assemblies, 64–66 making Web service calls, 62 mapping assemblies into AppDomains, 54 points to remember, 66–67 problem outlined, 52 running WSDL generator, 63 shadow copying, 58 using multiple AppDomains, 52 dynamically loading assemblies solution, 47, 50–51 implementing of factory, 51 points to remember, 52 three-assembly architecture, 48–49 wrapping in declaration of Net Generics class, 50 DynamicMock class, 22 211 7443Index.qxd 212 9/21/06 4:10 PM Page 212 ■INDEX G I gacutil command versioning assemblies, 45 garbage collection and delegates, 41–43 GenerateOrder method applying Visitor pattern to, 27 OrderManager class, 26 German formatting rules, 94–95 German ü conversion example, 86–87 converting text using Unicode, 88 GetBytes method Encoding class, 85 GetEncoding method Encoding class, 88 GetEnumerator method IEnumerable interface, 118 GetHashCode function implementing, 67–71 points to remember, 71 GetInvocationList method Delegate class, 160 Getting Started With NUnit example source code to be tested, testing addition of two numbers, testing additon of large numbers, testing failing contexts, granular code, 14 IApplicationMarker interface, 164 ICloneable interface cloning objects, 177 ICollection interface, 194 extended by IList interface, 196 ICommand interface, 77 Execute method, 154 minimalism of, 154 IComparable interface, 197 CompareTo method, 197 IComponent interface, 75 defining, 74 identifiers resolving into types and assemblies, 61–62 IEnumerable interface extended by IList interface, 196 GetEnumerator method, 118 IEnumerator interface extended by IList interface, 196 instantiating, 118 MoveNext method, 119, 121 IExtension interface casting IMarker to, 158 implementing, 158–159 IHashCodeProvider interface System.Collections namespace, 67 ILDASM.exe reverse engineering, 118 IList interface defining functor proxies, 196 IMarker interface casting to IExtension interface, 158 converting to a delegate, 160 extending, 157 implementing, 159 implementing dependencies, 157–164 IMarker Object Reference dependency IMarker interface, 156 implementing, 157 implementing using Extension pattern, 158 IMarker State dependency compared to Application Object Reference, 161 IMarker interface, 156 implementing, 160–161 IMarker State Exchange dependency IMarker interface, 156 implementing, 162 immutability and scalability, 187–191 appending string to existing string, 97 creating immutable classes, 188, 191 Nullable instance example, 148 H Handler class types naming conventions, 137 HashCodeAutomater class Append method, 69 implementation begin, 68 implementation end, 69 Hashtable class querying if value exists, 167 heap modifications to reference types, 33–41 storing reference types, 31 hexadecimal conversion example, 92 HexNumber value NumberStyles enumeration, 92 hidden dependencies as problematic, 24 HigherMath class fixing, 18 layered approach with fake objects, 15 Power method, 12 TestPower test method, 14 hot-plug assemblies, 47 7443Index.qxd 9/21/06 4:10 PM Page 213 ■INDEX L LastIndexOf method String class, 103–104 layered testing architecture, 14 layers identifying, 13 implementing, 18 layered approach with fake objects, 15 layered testing architecture, 14 legacy-code See inherited code List class ToString method, 105 Load method Assembly class, 47–48 lock keyword, 188 lookup tables, 87 M major numbers, 43 Making ToString Generate Structured Output example, 111 marker interfaces and their dependencies, 156 implementing dependencies, 157–164 using, 153–154 marshal by value, caution, 60 Mathematics class Add method, 7, 10 additional contexts for testing, 17 declaring as interface, 24 layered approach with fake objects, 15 Multiply method, 12, 19 TestAdd test method, TestAddLargeNumbers test method, testing addition of two numbers, TestMultiply test method, 14 Mediator pattern, 164 as extension of Application Object Reference, 163 decouples IMarker implementations, 164 Message method OutputToBeMocked class, 22 minor numbers, 44 Mock class, 22 mock objects creating by converting a fake object, 22 example, 19 implementing with trace log, 18 introduction, 19 mocking OutputToBeMocked class, 22 solution to feedback failure, 21 using for incursion, 25 Mono C# compiler and late binding, 83 MoveNext method generated MSIL, 121 IEnumerator interface, 119, 121 MulticastDelegate class System namespace, 42 multiplication by context, 15, 17 Multiply method Mathematics class, 12, 19 Multiply operator using in HigherMath.Power, 12 N namespaces naming conventions, 135–136 naming conventions classes and interfaces, 136–139 namespaces, 135–136 Navigation identifiers naming conventions, 138 Nested Private Class Bridge pattern, 151–153 new keyword, 126, 128, 134, 208 using with NET Generics, 82–84 NET 2.0 overloads for AppDomain.CreateDomain, 55 Find it faster at http://superindex.apress.com/ ImmutableData class, 75 incursion using mocks, 25 IndexOf method String class, 101–104 IndexOfAny method String class, 102, 104 inheritance, 123–127 having two methods return different types, 141 inherited code, 11 benefits of using fake objects in layers, 15 problems with contexts, 13 int class Parse method, 90 TryParse method, 90 IntelliSense using bottom-up approach, 1–2 interfaces creating instances with Factory pattern, 171–173 decoupling from implementation, 148 implementing, 128–135 implementing layers and modules, 18 marker interfaces, 153–154 naming conventions, 139 internal attribute testing types which use, InvalidOperation exception System namespace, 147 IParent interface, 77 is operator, 80 ISupportVisitor interface, 27 IVisitor interface Process method, 27 213 7443Index.qxd 214 9/21/06 4:10 PM Page 214 ■INDEX NET Generics, 27 as black boxes, 72 converting properties into a method, 144 embedding Generics declarations, 74–75 implementing a universal data converter, 79 implementing Command-like pattern, 72–73 implementing conversions, 80–81 implementing searches, 77 methods, 76 methods compared to type-level Generics, 79 overloading return parameters, 144 parameter explosions, 77, 81 points to remember, 75 points to remember when using methods, 81 using method-level parameter, 77–78 using methods to convert input to output type, 79 using new and class keywords, 82–84 newobj keyword, 82 nightly version, 44 Nmock library, 21 Null Object pattern and collections, 169 and Decorator pattern, 169 and Proxy pattern, 169 implementation, 167–169 null values not always a null state, 165–169 Nullable class System namespace, 146–148 nullable types not always a null, 145–148 parsing and verifying, 91 parsing numbers, 90 problem of inconsistent state, 165 returning a reference type from a method, 166–167 numbers See parsing from numbers to buffers NumberStyles enumeration using values to parse numbers, 92 NUnit, analyzing failures, 17 introduction, 2–5 nunit–console.exe, nunit–gui.exe, nunit.framework.dll, O Object class Add method, type as black box, 72 OOP (object-oriented programming) contradiction with TDD, 26 open source software release versions, 44 OrderManager class GenerateOrder method, 26 state generated by, 29 OrderManagerState class instantiating, 28 out keyword, 32 modifications to reference types, 33 OutputGenerator class converting into fake object, 23 solution to feedback failure with mock objects, 21 WriteIt method, 20 OutputToBeMocked class Message method, 22 overflow context, 8–9, 17 OverflowException attribute, 10 overloaded return type and property using, 140–145 overloading, implemented interface methods, 132 override keyword, 127–128, 132–135, 141 P parameter explosions, 76–77 parameters, avoid without identity, 205–208 Parse method DateTime class, 95 int class, 90 parser keyword, 137 parsing a string into an integer, 89–90 parsing from numbers to buffers, 89 managing culture information begin, 93 managing culture information end, 96 processing numbers in different cultures begin, 89 processing numbers in different cultures end, 92 partial classes, testing object’s internal state, 30 patch numbers, 44 points to remember, 41 polymorphism and consistency violations, 182–183 Power method analyzing failure of, 17 HigherMath class, 12 Predicate functor, 195, 200–201 PredicateProxy class, 197 Process method IVisitor interface, 27 visitor class, 28 Prototype pattern, 177 Provider class types naming conventions, 137 7443Index.qxd 9/21/06 4:10 PM Page 215 ■INDEX Proxy pattern, 194–195 and Null Object pattern, 169 combining with functor, 197 implementing layers and modules, 18 public keyword, 129, 172 R S samples directory, scalable types and immutability, 187–191 server registration resolving identifiers into types and assemblies, 62 shadow copying, 58 simple number context, 7, 17 stable version, 44 stack changes in values, 31–41 storing value types, 31 State pattern, 114–115, 130 Strategy pattern, 130 String class Concat method, 98–99 IndexOf method, 101–104 IndexOfAny method, 102, 104 LastIndexOf method, 103–104 StringBuilder class Append method, 98–99 when to use, 97–100 StringComparison enumeration performing string case-insensitive search, 103 strings common string-building operations, 97 converting to arrays, 85–89 parsing into an integer, 89–90 using StringBuilder class, 98–99 strong names using with version numbers, 45 structs as value types, 31 autoboxing value and assigning to reference type, 37 points to remember, 41 Structural class types naming conventions, 138 System namespace InvalidOperation exception, 147 MulticastDelegate class, 42 Nullable class, 146–148 System.Collections namespace IHashCodeProvider interface, 67 System.Text namespace Encoding class, 85 T Target property, 160 Delegate class, 160 TDD (test-driven development), contradiction with OOP 26 , getting started, 2–5 introduction, 1–2 Test attribute defining tests, test-driven development See TDD TestAdd test method, Mathematics class, TestAddLargeNumbers test method creating overflow exception, 10 Mathematics class, TestClass class contexts for testing Mathematics, 17 TestMultiply method, 19 TestDriven.NET installing, TestFixture attribute defining test class, TestFixtureSetUp attribute initializing data before running the tests, 16 TestFixtureTearDown attribute destroying initialized data members, 16 testing classes naming conventions, 137 Testing Large Code Pieces example source that implements the exponentiation and multiplication operators, 11 testing Power method, 12 using fake objects, 15 testing strategies layers, 13 Find it faster at http://superindex.apress.com/ reference types compared to value types, 31, 38 manipulating in function calls, 31–38, 40 points to remember, 41 Regional and Language Options dialog box formatting of numbers, dates, and times, 94 Remote AppDomain class instantiation, 55 ResultType parameter, 77 return keyword, 34 reverse dependencies, 25 reverse engineering ILDASM.exe, 118 215 7443Index.qxd 216 9/21/06 4:10 PM Page 216 ■INDEX TestMultiply method TestClass class, 19 TestMultiply test method Mathematics class, 14 TestPower test method HigherMath class, 14 tests benefits of writing simultaneously with code, contexts, 6–11 code pieces that don’t give information back, 19–25 writing for code that has no or few tests, 11–18 writing in context of larger code bases, 18 Tests class TestTranslation method, 20 TestTranslation method Tests class, 20 text editing with Command pattern, 154–156 finding within text buffer, 101–104 text buffer finding text within, 101–104 text-related solutions, 85 Thread class CurrentCulture property, 93, 96 CurrentThread property, 93 throw keyword, 208 top-down approach compared to bottom-up, ToString method always implement, 104–106 disposable types, 111 generating structured output, 110–116 List class, 105 trace log implementing mock objects, 18 Tracer ToString Tracer example, 112–113 implementation of the converter, 115 Transformer functor, 196, 202 TransformerProxy class, 197 Translate method DoTranslation class, 20–21 feedback failure, 20 TryParse method int class, 90 Unload method AppDomain class, 59 unstable version, 44 Utility class types naming conventions, 138 V Value And Reference Type Confusion example, 31–41 value types compared to reference types, 31, 38 manipulating in function calls, 31–40 verification part of test, 10 verifying correctness of objects without access, 26–30 version numbers, 43 NET, 44 versioning assemblies, 43–46 assembly redirection example, 46–47 virtual keyword, 22, 127, 128, 133–135, 141 visitor class Process method, 28 Visitor pattern applying to GenerateOrder, 27 implementing, 27 purpose of, 27 using, 30 Visual Studio NET using with NUnit, 4–5 W Web Services Description Language See WSDL What Are Delegates example, 41–43 while loop converting from for loop, 122 WriteIt method OutputGenerator class, 20 WriteLine method Console class, 87, 121–122, 170 wsdl command, 62–63 WSDL files, converting into proxy, 62 X X-develop, XSLT, 110 U Y UML functor architecture, collections, 196 unbox command, 38 UniversalDataConverter class Convert method, 79 yield keyword, 108 uses, 117–123 using, 106–110 ... Devspace.HowToCodeDotNet01.TestingCodeThatIsAMess.PickedApart.TestClass.➥ TestPower() in c:\Documents and Settings\cgross\Desktop\projects\➥ HowToCodeDotNet➥ \Volume01\LibVolume01\TestingCodeThatIsAMess.cs:line... the code and the associated tests Granular code is modular code, which is easier to control and maintain Sometimes when writing granular code, you want to test a piece of code on its own However,... PM Page CHAPTER ■ TESTING YOUR CODE at Devspace.HowToCodeDotNet01.NUnitTest.TestMath.AddLargeNUmbers() ➥ in c:\Documents and Settings\cgross\Desktop\projects\HowToCodeDotNet\ Volume01\LibVolume01\GettingStartedWithNUnit.cs:line

Ngày đăng: 21/08/2012, 09:54

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan