Partial class was introduced in .Net 2.0 mainly for better handling of visual designer generated code. To be honest, I have never been a fan of the idea of a partial class since day one. Even though the claim was that partial class makes the end-user’s code look much cleaner, the sad truth was that it came into being as an engineering workaround to ensure the correct parsing of designer generated code. But to experienced programmers, whether the classes we are working on look clean or not doesn’t really matter. If you accidentally changed the .designer.cs or .designer.vb files, the IDE will have an equally hard time interpreting the changes. So, by putting machine generated code into a separate file (partial class), it just simply hides the code a little better than the #Region directive.

Besides no apparent added benefits, it seems that partial class can be very confusing at times as well, especially given how different languages (e.g. C# and VB.Net) handle them in a slightly different way.

Here I will give a concrete example.

Suppose that you are creating a windows service using Visual Studio 2005. If you created the service in C#, you would see three files generated by default:

cs.JPG

Service1.cs will be the one where you put in your code. Service1.Designer.cs has all the designer generated code (for example, if you drag anything from the toolbox the created code would land in here). And finally Program.cs contains a single static Main() method that runs the service process.

If you created the service in VB.Net however, you would see only one file generated by default:

vb.JPG

This is actually quite deceptive, since there is a Service1.Designer.vb file associated with service1.vb. But you can only see the designer file if you toggle the show all files button on the top). In VB.Net, the program file (e.g. program.vb) is missing as the designer class handles both designer code and the shared Main() method that runs the service process.

If you further inspect the service1 class, you will find another difference in the code generated for C# and VB.Net. In C#, service1.cs defines the partial class:

public partial class Service1 : ServiceBase

Whereas in VB.Net service1.designer.vb defines the partial class:

<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _

Partial Class Service1

Inherits System.ServiceProcess.ServiceBase

And only has the following definition in service1.vb:

Public Class Service1

This is where the trouble begins. Since VB.Net hides the designer class by default an inexperienced person might not aware that the service class is actually split into two files, with each being a partial class. Now suppose the end user adds a namespace to the service1 class (service1.vb). Since the Service1 class is inherited from System.ServiceProcess.ServiceBase and this class does not exist in the custom declared namespace, you will get an error hint on OnStart and OnStop methods (sub xxx cannot be declared Overrides because it does not override a sub in a base class). Aha, without knowing that the service class defined in service1.vb is just a partial class and both classes should be in the same name space (so the correct way is to change service1.designer.vb to use the same name space) the user might change the code to the following to get rid of the errors:

Namespace Test

Public Class Service1

Inherits ServiceProcess.ServiceBase

Indeed, the compilation errors are gone now. Unfortunately now there are two service classes (Service1 and Test.Service1) instead of just one. And whatever you do in Test.Service1 in service1.vb will not be executed since the Main function in service1.designer.vb executes Service1 in Service1.designer.vb instead of service1.vb.

ServicesToRun = New System.ServiceProcess.ServiceBase() {New Service1}

System.ServiceProcess.ServiceBase.Run(ServicesToRun)

This behavior can really frustrate people who rarely develop Windows Services and it might take quite some time for them to find out the cure (the name spaces change in service1.vb and service1.designer.vb must be in sync).

If you change the service namespace in the C# service in service1.cs however, you are better off since the class defined in service1.cs is marked as a partial class and the designer class was not hidden by default.

 

 

Be Sociable, Share!