Let's drill down on the members of the DirectorySearcher class so that we can begin to get a feel for how it works.
We have grouped the various properties of the DirectorySearcher class together by their intended use to help demonstrate how they work together.
The following properties help us limit how much of the directory we search and which objects we want to find in the parts we are searching. For performance and efficiency reasons, we should always try to keep our search as narrow as possible.
Client Search Performance/Efficiency Options
These settings affect how the search will perform from the client's perspective. These options can increase the efficiency of the client, or in the case of timeout settings, make it appear so.
[**] Available in .NET 2.0 only.
 Asynchronous support is not available using .NET 2.0. While this setting will toggle the underlying IDirectorySearch option, all that will happen is that SDS will consume it synchronously, so the net effect is that everything is synchronous in SDS. If asynchronous support is desired, System.DirectoryServices.Protocols (SDS.P) must be used.
These features change how the search will perform or what it will returnsometimes dramatically. These properties expose the different behaviors of the underlying directory. When we use any of these, we are no longer asking for a simple search, we are fundamentally changing the search behavior at some level.
 Aliases are not used in Active Directory or ADAM, so this feature is not discussed. In other LDAP directories, it is possible to have aliases on objects, and this feature controls how they are decoded.
Many of these features are advanced and are the topic of Chapter 5.
Server Performance/Efficiency Options
We can maximize performance or minimize strain on our servers with careful application of the following properties. Some of these are covered later in this chapter, and others are more advanced topics and are covered in Chapter 5 in the sections on timeouts and performance optimization.
Two key methods actually execute the search.
The FindAll method returns a SearchResultCollection containing all the search results for a given search configuration. Internally, this method will initiate a bind to the SearchRoot DirectoryEntry (if it was not previously bound), and will use the IDirectorySearch interface to execute the search.
The FindOne method returns a single SearchResult, representing the first result in the underlying result set. Internally, this method is calling the FindAll method and returning the first SearchResult from the SearchResultCollection. Developers are sometimes under the mistaken impression that this method is somehow faster or more efficient than the FindAll method. Since FindAll is always called, this of course is not the case.
While the vast majority of the functionality in SDS is contained in the DirectoryEntry and DirectorySearcher classes, they use a few ancillary classes for support. For searching purposes, we typically use two related classes.
A SearchResult represents a single item from a result set. This class contains the ResultPropertyCollection class that holds the attributes and values specified by the PropertiesToLoad collection. If no additional attributes are specified in PropertiesToLoad, all nonconstructed attributes are returned by default. SearchResult also contains a handy method called GetDirectoryEntry that returns a DirectoryEntry object representing the result.
Note: Use GetDirectoryEntry Only When a Modify Operation Is Required
Beginners with SDS often get used to using the DirectoryEntry object to read the properties of objects and are tempted to use GetdirectoryEntry to convert a SearchResult into a DirectoryEntry so that they can read its attribute values. Do not do this! Creating a new DirectoryEntry object will trigger at least one and maybe two or more additional searches to the directory in order to read an object's attributes. This is very expensive from a performance perspective, especially when performed in a loop over many results.
By comparison, SearchResult already has all of the attributes we need. They were returned as part of the search operation, so there is no additional network overhead to read them. If we are careful with our use of the PropertiesToLoad property, we can also just get the attributes we need and reduce the size of the data moved over the network, increasing our performance some more.
The primary reason to call GeTDirectoryEntry from SearchResult is if we need to modify something. We already discussed CRUD methods in Chapter 3, and we go into detail on modify attribute values in Chapter 6.
This collection of SearchResult instances represents the result set as accumulated by the server for a specific query. This class internally holds references to unmanaged resources, and as such should always explicitly be disposed using the Dispose method, just like DirectoryEntry and DirectorySearcher.
The Basics of Searching
Part I: Fundamentals
Introduction to LDAP and Active Directory
Introduction to .NET Directory Services Programming
Binding and CRUD Operations with DirectoryEntry
Searching with the DirectorySearcher
Advanced LDAP Searches
Reading and Writing LDAP Attributes
Active Directory and ADAM Schema
Security in Directory Services Programming
Introduction to the ActiveDirectory Namespace
Part II: Practical Applications
Part III: Appendixes
Appendix A. Three Approaches to COM Interop with ADSI
Appendix B. LDAP Tools for Programmers
Appendix C. Troubleshooting and Help