Partial Classes in More Depth
A partial class can be formed by any number of building blocks. However, all of the parts combined must form a valid class definition. Put another way, if two of the parts define the same method with the same signature, it is signaled as a compile error. The same happens with properties, constructors, and so forth. The merge occurs at the class level; two methods with the same name are considered overloads and are never merged into a larger method.
Likewise, you can't reference methods with the same name from one another in an inheritance-like fashion. Let's say it againat its core, partial classes are primarily a sophisticated form of text-merging and have nothing to do with inheritance and object-oriented programming.
Partial types are fully integrated into the Visual Studio .NET 2005 IDE. Whenever you type the keyword this (or Me, if you're using Visual Basic .NET) in any area of the source editor, you will experience full IntelliSense capabilities and see everything about the class, including the members defined in the other parts (see Figure 3).
Using Partial Classes
|Figure 3: IntelliSense works across the parts of the class.|
Visual Studio .NET 2005 makes intensive use of partial classes when generating code for Windows and Web forms. In general, for code generators, partial classes represent an effective tool to leverage for building complex blocks of code in an incremental way. As mentioned, this pattern is largely used within Visual Studio .NET 2005 but can be applied to similar, custom scenarios where your own generator tool operates.
In addition, you can use partial classes to logically break down large classes into smaller pieces, which can be very time-saving and advantageous in team work scenarios when implementing parallel development.
Partial classes also prove a handy feature when it comes to adding debug and trace capabilities to a class. One of the constituent parts could be stuffed with all of the debug, trace, and log functionality. In this way, adding and removing the debug layer is as easy as adding and removing the specified file, and it doesn't affect the overall behavior of the class.
Partial classes may also affect the design of the data access layer of distributed systems. It is normally advisable to keep data access code off business objects.
Business objects, though, need to work on data in an efficient way, and proper data structures, to make data flow into the business tier, must be figured out. In the end, a common problem for architects and developers is figuring out how the data is moved into the business tier. If business and data layers are physically separated, you must find collection classes, custom objects, and a technology for data serialization and deserialization. This is neither unusual nor uncommon; it's just one of the typical tasks for architects of distributed systems.
No doubt this represents a best practice for real-world systems of a certain complexity. But can you say the same for small-sized systems?
The design pattern and its principles remain valid, but with partial classes you can get the same "virtual" code separation within a single set of classes: the business tier. For example, you can create a business object as a partial class in which you distinguish two sets of functionality, facade and data access.
Let's consider a class named Customer. You can define methods for managing the customer within the application in a partial class named Customer.Facade.cs. Elsewhere in the project, perhaps saved within another folder, you can have a second set of methods to load, save and delete customer information to and from the database of choice. This second block belongs to a file named, for example, Customer.Data.cs. The two files end up forming the same class; each set of methods has full access to private members of the other block.
In this way, the data access methods could store data directly into the private members of the class. At the same time, the coupling between the business object and the persistence medium is minimal. You can modify the data access logic by tweaking the code in the file Customer.Data.cs. More, you can switch to another database by replacing the same file. You have the best of two worlds: a single file with full access to private members and a good deal of separation if you want to change persistence details or, perhaps, refactor data access.
Is this approach recommended? It depends. It surely provides you with an alternative. If you're a design and OOP purist, you're already putting a curse on me. So, guess what? In this case, I wouldn't even suggest this to you. On the other hand, if you're more open-minded and used to looking at final results, you might want to take a closer look at this approach.