Why Would I Ever Need to Use C# Nested Classes [duplicate]
Asked Answered
G

8

250

I'm trying to understand about nested classes in C#. I understand that a nested class is a class that is defined within another class, what I don't get is why I would ever need to do this.

Gwyn answered 4/7, 2009 at 21:49 Comment(4)
I wonder how many other questions have this exact same subject line? Come on, Dan! What about C# Nested Classes?Electoral
John, i agree that it was asked before, but both a search on "C# Nested Classes" and the Related panel on the right contain no direct duplicates. Blame it on SO search :-{Timisoara
You're right. There's a lot about them, but not "why". Closest I found was #454718, and you'd have to know that inner and nested meant the same thing. Maybe it's not search, but maybe this is actually the first at this level.Electoral
While I really get the point with "duplicate question" flagging, still can-t resist the internal emotional drive to share my impression that people around here are super trigger happy about shooting the "duplicate" flag. While these probably understand the programming languages way better then me - it's somehow appears that they have issues with proper interpretation of English, especially when a noob asks something. I'm happy to see you two guys caring enough to understand the difference in knowledge-levels at which one is facing his issue - good to have you here.Dagmar
D
299

A pattern that I particularly like is to combine nested classes with the factory pattern:

public abstract class BankAccount
{
  private BankAccount() {} // prevent third-party subclassing.
  private sealed class SavingsAccount : BankAccount { ... }
  private sealed class ChequingAccount : BankAccount { ... }
  public static BankAccount MakeSavingAccount() { ... }
  public static BankAccount MakeChequingAccount() { ... }
}

By nesting the classes like this, I make it impossible for third parties to create their own subclasses. I have complete control over all the code that runs in any bankaccount object. And all my subclasses can share implementation details via the base class.

Distal answered 5/7, 2009 at 15:20 Comment(3)
@EricLippert how would the constructor of base class be called in this case since it is private? And if the base class constructor cannot be called how can a derived class instance be created? Sorry if this is not related to the post but I am just trying to understand the code and its useGillyflower
@EricLippert Ok a nested member can access members accessible to containing type, got itGillyflower
Right. Private means accessible in the type. Nested members are by definition in the type.Distal
C
134

The purpose is typically just to restrict the scope of the nested class. Nested classes compared to normal classes have the additional possibility of the private modifier (as well as protected of course).

Basically, if you only need to use this class from within the "parent" class (in terms of scope), then it is usually appropiate to define it as a nested class. If this class might need to be used from without the assembly/library, then it is usually more convenient to the user to define it as a separate (sibling) class, whether or not there is any conceptual relationship between the two classes. Even though it is technically possible to create a public class nested within a public parent class, this is in my opinion rarely an appropiate thing to implement.

Chetnik answered 4/7, 2009 at 21:51 Comment(14)
In fact, the .NET Framework Guidelines explicitly recommend against creating public nested classes.Winzler
@Mark: I wasn't aware of that, but it definitely makes sense. They are usually only appropiate as private/protected or in the rare case internal (when acesss from without the class isn't common).Chetnik
@Henk: I think Mark is referring to this page: msdn.microsoft.com/en-us/library/tdz1bea9(VS.71).aspxChetnik
The public-inside-public class can be useful, for example on factories: new MyObject.Factory() on which the create() would return a MyObject instance. Not really sure if this applies to C#, but I suppose it's a general design pattern.Leanora
@Jon: The factory pattern applies perfectly well to C#. However, the factory class is usually defined directly within the namespace (i.e. not nested), which makes sense in this case.Chetnik
One more example that MS doesn't adhere to its own recommendation: Just see System.Windows.Forms.ListView nested classes!Sarpedon
@Noldorin, @Mark: that page merely advices against public constructors on nested classes.Timisoara
@Henk: Actually, the second line states "Public nested types should be used rarely". The "both" conditions it then refers to, I am not sure about, however (there is only one bullet point).Chetnik
@Mehrdad: Indeed, that is the case. I have found it to be a slight nuisance when wanting to use ListViewItem objects in code.Chetnik
@Noldorin: Same for me. Fortunately var has fixed the issue nowadays... too late, now we have WPF!Sarpedon
@Mehrdad: Yeah, exactly. var is (almost) always your friend. WinForms apps haven't yet disappeared though, so it still helps. :)Chetnik
Better MSDN article on this - msdn.microsoft.com/en-us/library/ms229027.aspxTransmittal
If a public nested class has a private constructor; then it is totally valid to have a public nested class. Some rules are rules and some rules are opinions.Chante
@dravel: Yeah, that's a fair enough exception to the rule of thumb.Chetnik
S
54

A nested class can have private, protected and protected internal access modifiers along with public and internal.

For example, you are implementing the GetEnumerator() method that returns an IEnumerator<T> object. The consumers wouldn't care about the actual type of the object. All they know about it is that it implements that interface. The class you want to return doesn't have any direct use. You can declare that class as a private nested class and return an instance of it (this is actually how the C# compiler implements iterators):

class MyUselessList : IEnumerable<int> {
    // ...
    private List<int> internalList;
    private class UselessListEnumerator : IEnumerator<int> {
        private MyUselessList obj;
        public UselessListEnumerator(MyUselessList o) {
           obj = o;
        }
        private int currentIndex = -1;
        public int Current {
           get { return obj.internalList[currentIndex]; }
        }
        public bool MoveNext() { 
           return ++currentIndex < obj.internalList.Count;
        }
    }
    public IEnumerator<int> GetEnumerator() {
        return new UselessListEnumerator(this);
    }
}
Sarpedon answered 4/7, 2009 at 21:52 Comment(2)
Additionally, I find the internal working of how a foreach works absolutely amazing. Thanks!Resistive
I really appreciate this example. I think for many new C# people there are lots of hidden assumption and processes going on not described. For example, there's four hidden interfaces working in tandem here: IEnumerable<T>, IEnumerable, IEnumerator<T>, and IEnumerator. The parent class is assumed to be a List<int> object with stored numbers. And "foreach" would call GetEnumerator when looping through the list. Too much complexity missed....Cassity
W
53

what I don't get is why I would ever need to do this

I think you never need to do this. Given a nested class like this ...

class A
{
  //B is used to help implement A
  class B
  {
    ...etc...
  }
  ...etc...
}

... you can always move the inner/nested class to global scope, like this ...

class A
{
  ...etc...
}

//B is used to help implement A
class B
{
  ...etc...
}

However, when B is only used to help implement A, then making B an inner/nested class has two advantages:

  • It doesn't pollute the global scope (e.g. client code which can see A doesn't know that the B class even exists)
  • The methods of B implicitly have access to private members of A; whereas if B weren't nested inside A, B wouldn't be able to access members of A unless those members were internal or public; but then making those members internal or public would expose them to other classes too (not just B); so instead, keep those methods of A private and let B access them by declaring B as a nested class. If you know C++, this is like saying that in C# all nested classes are automatically a 'friend' of the class in which they're contained (and, that declaring a class as nested is the only way to declare friendship in C#, since C# doesn't have a friend keyword).

When I say that B can access private members of A, that's assuming that B has a reference to A; which it often does, since nested classes are often declared like this ...

class A
{
  //used to help implement A
  class B
  {
    A m_a;
    internal B(A a) { m_a = a; }
    ...methods of B can access private members of the m_a instance...
  }
  ...etc...
}

... and constructed from a method of A using code like this ...

//create an instance of B, whose implementation can access members of self
B b = new B(this);

You can see an example in Mehrdad's reply.

Warfourd answered 5/7, 2009 at 1:51 Comment(2)
the advantage is only item 1, if you exclude it, you can use protected, thus "using private fields" becomes thing-in-itselfLixiviate
The nested class isn't necessarily a subclass (which can use protected). For example, the outer class might be some kind of container, and the nested class might be an iterator for that container: the iterator wants access to the member data / implementation details of the container.Warfourd
M
39

There is good uses of public nested members too...

Nested classes have access to the private members of the outer class. So a scenario where this is the right way would be when creating a Comparer (ie. implementing the IComparer interface).

In this example, the FirstNameComparer has access to the private _firstName member, which it wouldn't if the class was a separate class...

public class Person
{
    private string _firstName;
    private string _lastName;
    private DateTime _birthday;

    //...
    
    public class FirstNameComparer : IComparer<Person>
    {
        public int Compare(Person x, Person y)
        {
            return x._firstName.CompareTo(y._firstName);
        }
    }
}
Molotov answered 5/7, 2009 at 2:15 Comment(4)
Except, the FirstNameComparer class should be static, as well as the Compare method.Paigepaik
@erike: not if your implementing the IComparer<T> interface, as I did...Molotov
I suppose that you are right!Paigepaik
you can use this scenario with private nested and create static method to expose the instance of IComparer in the Top level class. cause in this case nested class is not useful for other classes so make instance privatly rather than give control to other'sTattered
T
20

There are times when it's useful to implement an interface that will be returned from within the class, but the implementation of that interface should be completely hidden from the outside world.

As an example - prior to the addition of yield to C#, one way to implement enumerators was to put the implementation of the enumerator as a private class within a collection. This would provide easy access to the members of the collection, but the outside world would not need/see the details of how this is implemented.

Temperamental answered 4/7, 2009 at 21:52 Comment(2)
Which has the added benefit that code using such an implemented interface cannot sneakily cast the interface back to the implementing class, because it is nested and private so it cannot be referenced.Triclinic
@Triclinic That is actually quite significant! +1 for sure as it keeps code even more secure.Recuperator
S
6

Nested classes are very useful for implementing internal details that should not be exposed. If you use Reflector to check classes like Dictionary<Tkey,TValue> or Hashtable you'll find some examples.

Shrunk answered 4/7, 2009 at 22:48 Comment(0)
W
4

Maybe this is a good example of when to use nested classes?

// ORIGINAL
class ImageCacheSettings { }
class ImageCacheEntry { }
class ImageCache
{
    ImageCacheSettings mSettings;
    List<ImageCacheEntry> mEntries;
}

And:

// REFACTORED
class ImageCache
{
    Settings mSettings;
    List<Entry> mEntries;

    class Settings {}
    class Entry {}
}

PS: I've not taken into account which access modifiers should be applied (private, protected, public, internal)

Wideeyed answered 31/12, 2011 at 14:36 Comment(1)
Unfortunately when doing this, the convention of public Settings Settings { get; set; } goes out the window.Harmless

© 2022 - 2024 — McMap. All rights reserved.