For a sucessful technology, honesty must take precedence over public relations for nature cannot be fooled. --Richard Feynman

Partial Classes in .NET

The partial class concept in Visual Studio 2005

Downloads

  • Partial Classes Demo (14.1KB) - Visual Studio 2005, .NET 2.0 project demonstrating partial classes

Summary

If you're new to .NET 2.0, then you're new to the concept of partial classes. Partial classes simply allow a single class definition to span more than one file offering yet another useful way to organize your code.

First a basic example. Following is a simple class definition in C# which spans two files: Statistics_Public.cs and Statistics_Local.cs. This is just one possible way (and not a great one) that you might want to break up your code into separate files so that it is easier to manage.

If you come from the C or C++ world where you are used to include files and source files (mycode.h, mycode.c), then you could break up your code that way still perhaps naming your partial class files mycode.h.cs and mycode.cs.

Statistics_Public.cs partial class file

// filename: Statistics_Public.cs
namespace Cambia.PartialClasses
{
    public partial class Statistics
    {
        // basic sum
        public decimal Sum(decimal[] nums)
        {
            decimal sum = 0;
            foreach ( decimal d in nums )
                sum += d;
            return sum;
        }
        // sum only the even indexes: 0, 2, 4, 6 ...
        public decimal SumEvens( decimal[] nums )
        {
            decimal[] evens = GetEvens(nums);
            return Sum(evens);
        }
    }
}

Statistics_Local.cs partial class file

// filename: Statisics_Local.cs
namespace Cambia.PartialClasses
{
    public partial class Statistics
    {
        internal decimal[] GetEvens( decimal[] nums )
        {
            decimal[] outputNums = new decimal[(nums.Length+1)/2];
            for ( int i=0; i<nums.Length; i=i+2 )
                outputNums[i/2] = nums[i];
            return outputNums;
        }

    }
}

For this little example, breaking your code into separate files would be pretty silly. But there are cases where partial classes are useful.

Visual Studio uses partial classes to separate auto-generated code from user-generated code. For example, in the Windows Form application I created for this example my main form is named Form1 and the main code that I will write resides in Form1.cs, just as in previous version of Visual Studio.

The app itself is very simple and uses the Statistics class to add the even numbered lines in a list (where numbering starts with 0).

The main code file for the form looks like this. Note the use of the 'partial' keyword on the class definition.

Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Cambia.PartialClasses
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click( object sender, EventArgs e )
        {
            string[] lines = textBox1.Lines;
            List<decimal> nums = new List<decimal>();
            try
            {
                foreach ( string line in lines )
                {
                    if ( line.Trim() == "" )
                        nums.Add(0);
                    else
                        nums.Add(Convert.ToDecimal(line));
                }
                Statistics stats = new Statistics();
                decimal sum = stats.SumEvens(nums.ToArray());
                textBox2.Text = sum.ToString();
            }
            catch ( Exception ex )
            {
                MessageBox.Show("Error parsing numbers.  "
                                + "Please enter 1 number per line.");
            }
        }
    }
}

But wait! Where are my buttons, labels and textboxes defined?

I know, I know. You're ahead of me already if you're even bothering to read my commentary, so I won't belabor it any longer.

Visual Studio creates a file called Form1.Designer.cs which holds the designer-related, auto-generated code. So in both Form1.cs and Form1.Designer.cs the Form1 class is declared as partial and the compiler joins them into one.

Note that Visual Studio does not have a partial designer class for ASP.NET. It is generated at runtime.

Form1.Designer.cs

namespace Cambia.PartialClasses
{
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be 
        /// disposed; otherwise, false.</param>
        protected override void Dispose( bool disposing )
        {
            if ( disposing && ( components != null ) )
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.button1 = new System.Windows.Forms.Button();
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.textBox2 = new System.Windows.Forms.TextBox();
            this.label1 = new System.Windows.Forms.Label();
            this.SuspendLayout();
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(156, 50);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(99, 23);
            this.button1.TabIndex = 0;
            this.button1.Text = "Sum Evens >";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Click += new System.EventHandler(this.button1_Click);
            // 
            // textBox1
            // 
            this.textBox1.Location = new System.Drawing.Point(4, 50);
            this.textBox1.Multiline = true;
            this.textBox1.Name = "textBox1";
            this.textBox1.Size = new System.Drawing.Size(146, 124);
            this.textBox1.TabIndex = 1;
            // 
            // textBox2
            // 
            this.textBox2.Location = new System.Drawing.Point(261, 50);
            this.textBox2.Multiline = true;
            this.textBox2.Name = "textBox2";
            this.textBox2.Size = new System.Drawing.Size(145, 124);
            this.textBox2.TabIndex = 2;
            // 
            // label1
            // 
            this.label1.Location = new System.Drawing.Point(1, 9);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(405, 38);
            this.label1.TabIndex = 3;
            this.label1.Text = "Enter one number per line in the left box."
            + "  Then click the button to sum every ot" 
            + "her one starting with the first.";
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(407, 178);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.textBox2);
            this.Controls.Add(this.textBox1);
            this.Controls.Add(this.button1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.Button button1;
        private System.Windows.Forms.TextBox textBox1;
        private System.Windows.Forms.TextBox textBox2;
        private System.Windows.Forms.Label label1;
    }
}