【问题标题】:Nested class with hidden constructor impossible in c#?c# 中不可能隐藏构造函数的嵌套类?
【发布时间】:2010-03-13 21:56:22
【问题描述】:

我最近一直在做一些编程,遇到了一个我发现在 c# 中很奇怪的问题。 (至少对我来说)

public class Foo
{
    //whatever
    public class FooSpecificCollection : IList<Bar>
    {
         //implementation details
    }
    public FooSpecificCollection GetFoosStuff()
    {
         //return the collection
    }
}

我希望 Foo 的使用者能够获得对 FooSpecificCollection 的引用,甚至对其执行一些操作。甚至可能将其设置为 Foo 或类似的其他属性,但不能创建此类的实例。 (应该能够实例化这个集合的唯一类应该是 Foo。

我的要求真的那么牵强吗?我知道人们更聪明地定义了 c#,但不应该有这样一个选项,即父类可以创建嵌套类实例,但其他人不能。

到目前为止,我创建了一个解决方案,通过属性使抽象类或接口可用,并实现在其他任何地方都不可用的具体私有类。

这是处理这种情况的正确方法吗?

【问题讨论】:

  • 好奇:是否会有多个 'Foo 实例,每个实例都有自己独特的 'FooSpecificCollection ?
  • 是的,就是这样。假设每个客户端都有一个 Foo 实例(它将由工厂在某个精确的时间创建),而 Foo 将为自己创建一个 FooSpecificCollection。我允许访问 foo 特定的集合,以便人们知道 foo 里面有什么,我让他们玩这些项目,但他们不应该能够创建一个,因为这没有什么意义。在晚上我想也许我试图让这段代码有太多的语义:)

标签: c# programming-languages language-features


【解决方案1】:

嵌入式类的工作方式是,它们作为外部类的成员,可以访问该外部类的私有成员。但不是相反(你想要什么)。

您可以屏蔽 FooSpecificCollection 的构造函数,但工厂必须是 FooSpecificCollection 本身的一部分。它可以招募外部类:

public class Foo
{
    public class FooSpecificCollection : List<Bar>
    {
         private FooSpecificCollection ()   { }

         public static FooSpecificCollection GetFoosStuff()
         {
            var collection = new FooSpecificCollection ();
            PrepareFooSpecificCollection(collection);
            return collection;            
         }
    }

    private static void PrepareFooSpecificCollection(FooSpecificCollection collection)
    {
         //prepare the collection
    }
}

【讨论】:

  • 可能你是对的:)它非常类似于工厂模式(我实际上考虑过)。
  • 总是从你的回答中学到一些东西,谢谢,Henk。在这种情况下,如果有多个 'Foo 实例会发生什么?
  • @BillW,如果你真的要使用这种模式,你可能必须通过 GetFooStuff() 传递一个 Foo 的实例,然后再传递给 PrepareFooSpecificCollection()。
【解决方案2】:

将您的嵌套类设为private,并将GetFoosStuff 的返回值设为IList&lt;Bar&gt; 而不是FooSpecificCollection

另外,deriving from List&lt;Bar&gt; is a bug 很有可能。

【讨论】:

  • 我来自 List 而不是 foo
  • 对不起,我的意思当然是 IList。 List 将是内部实现。但这不是问题所在。但是感谢您的警惕:)
  • 只是好奇您所说的“从List&lt;Foo&gt; 派生是一个错误”是什么意思。我查看了链接,但找不到任何表明从 List&lt;T&gt; 派生本身存在问题的内容。
  • 99% 的情况下,当您声称某个东西是 List 时,您实际上想说的是它是 T (IEnumerable) 的枚举。它可以工作,但是在返回类型中过于具体是糟糕的设计。
【解决方案3】:

如果您正在创建一个库供其他人使用,您可以将构造函数设为internal。图书馆外的任何人都无法访问它。如果您担心在自己的项目中调用构造函数,请不要在父类之外调用它。

我们总是创建与其他类不直接相关的类,但构造函数不必对不相关的类隐藏。我们(程序员)知道这些对象是不相关的,所以我们永远不会在另一个中创建一个实例。

【讨论】:

    【解决方案4】:

    有一个解决方案,但我认为我不会在我的应用程序中使用它 :) 这个想法是从 FooSpecific 派生类,它是私有的,只能在 Foo 内部使用,但具有公共构造函数,因此 Foo 可以创建它的实例。

    public class Foo
    {
        //whatever
        public class FooSpecific
        {
            // Protected contructor.
            protected FooSpecific()
            {
            }
    
            // All other code in here.
        }
    
        // Private helper class used for initialization.
        private class FooSpecificInitHelper : FooSpecific
        {
            public FooSpecificInitHelper()
            {
            }
        }
    
        // Method in foo to create instaces of FooSpecific.
        private FooSpecific CreateFooSpecific()
        {
            return new FooSpecificInitHelper();
        }
    }
    

    【讨论】:

      【解决方案5】:

      不,这真的没有意义。

      我的意思是,你可以潜在地返回其他实例;但是谁会从那个类派生呢?当然不是任何其他类(因为那是错误的,并且暗示它不应该隐藏在主类中),所以...

      【讨论】:

      • 我想在嵌套类中有一些功能,这些功能清晰简洁,易于阅读和使用(例如,某些 FOO 内部集合上的漂亮界面)。而且我不想让人们创建那个类。当然,无论如何他们不应该有任何业务,但我仍然想要一个明确的语义说 - 这个类可以帮助你操作一些 Foo 的东西,但是 Foo 也给了你它,你不应该自己创建它......内部在装配中是可以的,但我没有得到你的答案,为什么它没有意义。我希望使用我的类的开发人员不要尝试实例化它……为什么这毫无意义?
      • 这里除了派生类还有其他问题。
      • luckyuke:所以让构造函数私有?我以为你试图阻止外部类创建它的实例。
      猜你喜欢
      • 1970-01-01
      • 2016-10-07
      • 2012-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      • 2015-07-03
      相关资源
      最近更新 更多