为什么我需要使用 C# 嵌套类

发布于 2024-07-26 07:51:58 字数 58 浏览 2 评论 0原文

我试图了解 C# 中的嵌套类。 我知道嵌套类是在另一个类中定义的类,我不明白的是为什么我需要这样做。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

国粹 2024-08-02 07:51:58

我特别喜欢的一种模式是将嵌套类与工厂模式结合起来:

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() { ... }
}

通过像这样嵌套类,我使第三方无法创建自己的子类。 我可以完全控制在任何银行帐户对象中运行的所有代码。 我的所有子类都可以通过基类共享实现细节。

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.

鱼忆七猫命九 2024-08-02 07:51:58

目的通常只是限制嵌套类的范围。 与普通类相比,嵌套类具有 private 修饰符的额外可能性(当然还有 protected)。

基本上,如果您只需要在“父”类中使用此类(就范围而言),那么将其定义为嵌套类通常是合适的。 如果此类可能需要在没有程序集/库的情况下使用,那么用户将其定义为单独的(兄弟)类通常会更方便,无论是否存在任何概念关系两个班级之间。 尽管在技术上可以创建一个嵌套在 public 父类中的 public 类,但在我看来,这很少是一个合适的实现方式。

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.

是伱的 2024-08-02 07:51:58

嵌套类可以具有 privateprotectedprotected inside 访问修饰符以及 publicinternal< /代码>。

例如,您正在实现返回 IEnumerator 对象的 GetEnumerator() 方法。 消费者不会关心对象的实际类型。 他们所知道的只是它实现了该接口。 你想要返回的类没有任何直接的用途。 您可以将该类声明为 private 嵌套类并返回它的实例(这实际上是 C# 编译器实现迭代器的方式):

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);
    }
}

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);
    }
}
南薇 2024-08-02 07:51:58

我不明白的是为什么我需要这样做

我认为你永远需要这样做。 给定一个像这样的嵌套类......

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

你总是可以将内部/嵌套类移动到全局范围,就像这样......

class A
{
  ...etc...
}

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

但是,当B仅用于帮助实现A时,则使B成为内部/嵌套类有两个优点:

  • 它不会污染全局范围(例如,可以看到 A 的客户端代码甚至不知道 B 类存在)
  • B 的方法隐式可以访问 A 的私有成员; 而如果 B 没有嵌套在 A 中,B 将无法访问 A 的成员,除非这些成员是内部或公共的; 但如果将这些成员设置为内部或公开,也会将它们暴露给其他类(不仅仅是 B); 因此,将 A 的这些方法保留为私有,并通过将 B 声明为嵌套类来让 B 访问它们。 如果您了解 C++,这就像说在 C# 中,所有嵌套类自动成为包含它们的类的“朋友”(并且,将类声明为嵌套类是唯一的方法在 C# 中声明友谊,因为 C# 没有 friend 关键字)。

当我说 B 可以访问 A 的私有成员时,这是假设 B 具有对 A 的引用; 它经常这样做,因为嵌套类通常是这样声明的……

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...
}

并使用这样的代码从 A 的方法构造……

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

您可以在 Mehrdad 的回复中看到一个示例。

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.

停滞 2024-08-02 07:51:58

公共嵌套成员也有很好的用途...

嵌套类可以访问外部类的私有成员。 因此,在创建比较器(即实现 IComparer 接口)时,这是正确的方法。

在此示例中,FirstNameComparer 可以访问私有 _firstName 成员,如果该类是一个单独的类,则不会访问该成员...

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);
        }
    }
}

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);
        }
    }
}
菩提树下叶撕阳。 2024-08-02 07:51:58

有时,实现从类内部返回的接口很有用,但该接口的实现应该对外界完全隐藏。

举个例子 - 在 C# 中添加 Yield 之前,实现枚举器的一种方法是将枚举器的实现作为私有类放入集合中。 这将提供对集合成员的轻松访问,但外界不需要/查看其实现方式的细节。

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.

为人所爱 2024-08-02 07:51:58

嵌套类对于实现不应公开的内部细节非常有用。 如果你使用 Reflector 检查像 Dictionary这样的类 或 Hashtable 你会找到一些例子。

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.

我不咬妳我踢妳 2024-08-02 07:51:58

也许这是何时使用嵌套类的一个很好的例子?

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

并且:

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

    class Settings {}
    class Entry {}
}

PS:我没有考虑应该应用哪些访问修饰符(私有、受保护、公共、内部)

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)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文