可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This question already has an answer here:
-
Why/when should you use nested classes in .net? Or shouldn't you?
13 answers
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.
回答1:
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.
回答2:
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.
回答3:
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);
}
}
回答4:
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.
回答5:
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 seperate 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._lastName);
}
}
}
回答6:
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.
回答7:
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.
回答8:
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)