Using partial classes with nested classes for maintainability
C# allows you to create nested classes - that is, classes that exist "within" a different class. Depending on what visibility you give these classes, they can be just as public as anything else (the Environment.SpecialFolder enumeration is such an example). If you use 'internal', other classes in the assembly will be able to see it, but not classes in other assemblies.
The special thing about nested classes is that you can declare them as private (the default), in which case only the containing type gets to access the class. This allows for a more controlled usage of the class, and is great for helper classes that should only be used by a single class.
One of the problems you may run into when using nested types is that if they have any reasonable size at all, it's likely that the file in which they're used ends up looking very odd - you usually end up with a much bigger file than in the rest of your project, and when you're on a method it may be difficult to tell which class the method is in. In a way, it breaks down the good advise of not having many classes in a single file.
Can you have your cake and eat it too? Of course (this would be a poor blog post otherwise I guess). Partial classes come to the rescue again. In this case we're not using them to be able to separate tool-generated from "us-"generated code, instead we're using them to separate a nested class into its own file.
To work on the previous example, let's say I have a file that declare a class Cs and uses a nested class NestedClass.
namespace
CsNamespace
{
public partial class Cs
{
public static void Main(string[] args)
{
// Here we can also refer to Cs.NestedClass as 'NestedClass'.
NestedClass instance = new Cs.NestedClass();
instance.FirstName = "Marcelo";
instance.LastName = "Lopez Ruiz";
System.Console.WriteLine(instance.FullName);
}
}
}
Now I can include this in a separate file and compile both of them together in the same project. Note that the class I've marked as partial is Cs - in this example, I have no need to mark NestedClass as partial, as its complete definition can be found in this single file.
namespace
CsNamespace
{
public partial class Cs
{
private class NestedClass
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName
{
get { return this.FirstName + " " + this.LastName; }
}
}
}
}
Other classes in the project will now need to "behave", and they can't break the encapsulation provided by the private nested class.
public class AnotherClass
{
public void Foo()
{
// Uncommenting this gives error, for example:
//
// error CS0122: 'CsNamespace.Cs.NestedClass' is
// inaccessible due to its protection level
//
// Cs.NestedClass instance = new Cs.NestedClass();
}
}
Enjoy!
Comments
Anonymous
April 13, 2009
Nested classes are evil. They have more potential to hurt readability, than any useful purpose. Inexperienced developers tend to use them all over the place, making the API babbler and unclear.Anonymous
April 13, 2009
Is FxCop rule CA1034 (NestedTypesShouldNotBeVisible) no longer valid?Anonymous
April 13, 2009
The comment has been removedAnonymous
April 15, 2009
I refuse to recognize the Internal/Friend class member :) (I consider the assembly-level to be a somewhat artificial construct - almost as if it's a confined by a point in time (build time) - compared to classes and namespaces and thus never, ever use it as a visibility level). I'm sure people have their reasons for using it, and I'm probably in the minority, but that's just the way I am.