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 (4)

  1. Yaakov says:

    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.

  2. Keith Patrick says:

    Is FxCop rule CA1034 (NestedTypesShouldNotBeVisible) no longer valid?

  3. @Keith – FxCop is mostly concerned about visibility from outside the assembly. Keeping a nested class private makes it hidden from types /within/ the assembly as well, which is a stronger form of information hiding. So it’s still valid – even more so you might say.

    @Yaakov – I agree with your statements in the general case. I’ve found them convenient for transient state machines though.

    First example that comes to mind is a component that does something like upload a file and is very property/method/event oriented (where you migth see a single high-level concept/type exposed). Stream/source + status + progress state and such are typically only useful when there’s something interesting going on, and it’s sometimes handy to encapsulate these to clarify that the lifetime of certain things is not necessarily the same as the other fields in the class.

    Of course you can make do with a different class within the assembly, but if it really should only be visible to its parent (because in a sense it /is/ part of its parent for its lifetime), then nested classes help convey this to other people that might be browsing the codebase. In a sense they hurt discoverability on purpose (again, it’s hopefully a ‘desired case’ of information hiding).

    On the other hand, there’s stuff like the Environment.SpecialFolders enum, which is just painful to use. Even though it /looks/ like it "belongs" to Environment, it’s actually /used/ by customers, and thus should not have been a nested type. I think that really, at the point where anyone will be refering to it from outside the parent scope, you’re better off making it a standalone, well-defined, useful top-level concept.

    Do you guys have other high-profile counter-examples for nested classes?

  4. Keith Patrick says:

    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.

Skip to main content