【问题标题】:Class hierarchy in C#: how to do it correctly? ('friend' keyword wanted)C# 中的类层次结构:如何正确执行? (需要“朋友”关键字)
【发布时间】:2011-04-17 03:41:16
【问题描述】:

我有一堂课:

public class MyClass {  
 private List<string> folderList;  
 // .... a lot of useful public methods here.....  
}  

一切都很好。文件夹列表被封装,类可通过公共方法访问。好的。现在我需要一个允许用户为 MyClass 选择文件夹的“选项”表单。有一个问题:新的 Setup 类必须有权访问私有 folderList 字段(或者我必须提供公共方法来获取和设置文件夹列表 - 它本质上是相同的)。在旧的好 C++ 中,我会使用“朋友”功能,因为除了安装程序类之外没有人可以访问文件夹列表。但是 C# 中没有“朋友”功能(我是 C# 世界的新手)。

附:其实我只是公开了 folderList,但我觉得有更好的解决方案。

谢谢。

【问题讨论】:

    标签: c# oop class hierarchy friend


    【解决方案1】:

    您可以使用“internal”关键字使您的方法仅在您的程序集/项目中可用,如果您想在其他项目或程序集中访问您的内部方法,那么您可以使用“InternalsVisibleTo”属性,您可以在其中访问您的内部仅在您为其定义此属性的程序集中。

    MSDN Internal Keyword

    【讨论】:

      【解决方案2】:

      我相信您要查找的关键字是internal。它大致等同于 C++ 的 friend

      Internal 提供程序集级别的可见性。

      结合 Femaref 使用属性的建议,您应该有完整的解决方案。

      【讨论】:

        【解决方案3】:

        我不确定这是否是他/她想要的。他/她没有提出潜在客户将在当前程序集中的要求......因此,在 c++ 中使用friend 时(这从未被认为是一种好的风格),您必须知道确切有权访问该成员的类的类型。如果这个类不是你正在编写的程序的一部分,你不能通过这种方式授予访问权限。

        如果您想有条件地访问某个类实例的某些属性或方法,则需要实现某种权利机制,例如:

        public IList<Folder> GetFolderList(Object pClient, IEntitlementService pService) {
         if (pService.IsEntitledToAccess(this, pClient) {
          return folderList;
         } else {
          throw new AccessNotGrantedException("...");
         }
        }
        

        我相信 .Net 框架中有内置实用程序用于此目的,只需去 google(或 bing)...

        【讨论】:

        • +1 服务架构很好,但有时对于较小的程序来说太复杂了。
        • 提问者肯定需要指定,访问类是否会(或不会)在同一个程序集中......如果你问我:他们不应该,因为他们显然有不同的担忧:逻辑与用户界面
        【解决方案4】:

        作为对这个问题的确切答案,我建议如下 - 创建一个单独的接口 IFolderList:

        interface IFolderList
        {
          IList<string> FolderList { get; }
          ...
        }
        

        嗯,你可以在界面中添加其他需要的成员

        在 MyClass 类中显式实现此接口。

        因此,Setup 类可以通过显式强制转换为接口 IFolderList 来访问数据,或者只使用这些接口。

        【讨论】:

          【解决方案5】:

          使internal 方法供Setup 类使用的替代方法是使用访问者模式并添加一个将Setup 类实例作为参数的方法,然后使用私有folderList根据需要初始化/更改Setup 状态。当然,这需要 Setup 类上的适当公共方法,因此可能不符合您的需求。

          【讨论】:

            【解决方案6】:

            公开folderList 字段是最坏的情况。通过公共字段或设计不佳的公共属性公开实现细节(公共字段和使用 getter 和 setter 的公共属性之间的集合没有区别)。

            对于公共字段,当您想要添加验证、更改通知、将其放入接口或将集合类型从一种类型更改为另一种类型时,您无法将字段提升为属性。

            顺便说一句,Jeffrey Richter 在框架设计指南的注释中提到 “就我个人而言,我总是将我的字段设为私有。我什至不将字段公开为内部字段,因为这样做会给我自己的程序集中的代码没有保护"

            我认为添加显式接口的最佳方式是向 MyClass 客户端公开严格的抽象。

            例如,您可以添加两个单独的方法来检索文件夹和将新文件夹添加到此存储:

            class MyClass {
              //You should return IList<string>
              public IList<string> MyList {get {return myList;} }
            
              //Or even IEnumerable<string>, because you should return
              //as minimal interface as your clients needs
              public IEnumerable<string> MyList {get {return myList;} }
            
              //You may expose this functionality through internal
              //method, or through protected internal method,
              //but you should avoid direct access to your implementation
              //even for descendants or another classes in your assembly
              public void AddElement(string s) {myList.Add(s);}
            
              private List<string> myList;
            }
            

            【讨论】:

              【解决方案7】:

              这就是 C# 中的属性:

              public class MyClass 
              {
                private List folderList;
              
                public List FolderList
                {
                  get {return folderList;}
                  set {folderList = value;}
                }
              }
              

              属性封装了私有字段,在设置时提供验证的可能性。此外,您应该阅读泛型(类似于 c++ 中的模板)并使用 List&lt;T&gt; 而不是 List 来获得强类型集合。

              但是,除非Setup 派生自MyClass,否则您可能无法实现您的计划。在这种情况下,您可以使用 protected 字段。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2013-10-08
                • 2015-05-14
                • 2013-11-21
                • 2015-11-01
                • 1970-01-01
                • 2011-02-24
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多