【问题标题】:Implementing friend (available in C++) functionality in C#在 C# 中实现朋友(在 C++ 中可用)功能
【发布时间】:2010-10-11 09:30:48
【问题描述】:

好吧,让我们离开关于友谊是否打破封装的争论,并实际尝试优雅地提出一个连贯的设计。这是一个双重功能:

1) 关于如何实施的一般问题:

  public class A 
   {
      friend class B;
   }


2) 为什么我需要这个功能?我的一些类实现了ISerializable 接口。但是,我想在 Derived 类中保护 ISerializable 方法,这样我就不会将它们暴露给客户端(以及在文档中)。但是,内部类应该能够访问它们。在 C# 中解决此问题的一般方法是什么?

注意:我使用的是当前 C++ 标准中定义的友谊。

谢谢

【问题讨论】:

    标签: c# .net c++ serialization


    【解决方案1】:

    C# 具有internal 关键字,因此同一程序集中的其他类型可以看到标记为内部的类型。此外,您可以将attributes 添加到程序集,以允许程序集外部的类型查看该程序集的内部成员。

    【讨论】:

    • 请提供一个例子。设计的目标是确保 CLIENT 对这种方法的存在一无所知。
    • 客户端可以随时使用反射来发现任何方法。
    【解决方案2】:

    internal 成员在当前 .dll 中是公共的,在外部是私有的。此外,您可以使用 InternalsVisibleTo 属性将它们公开给外部 .dll。

    【讨论】:

      【解决方案3】:

      如果类在同一个程序集中,您可以使用internal。如果它们在不同的程序集中,您可以使用friend assembly attribute

      【讨论】:

        【解决方案4】:

        InternalsVisibleTo 放在一边,在实现接口时只有两种选择:

        • 用公共方法实现它们
        • 使用显式接口实现来实现它们

        在这两种情况下,任何人都可以调用方法,但使用显式接口实现,您只能“通过”接口表达式调用方法(例如,您可以将实际类型的变量强制转换为 ISerializable)。

        没有“内部”实现接口这样的概念。

        【讨论】:

        • 这些是我的想法......但是为了争论,如果你尝试将接口实现方法标记为内部会发生什么?
        • 它将不再实现接口,你会得到一个编译时错误。不知道为什么我的回答被否决了,因为它实际上解决了这个问题......
        • 乔恩,你解决了问题的第一部分——事实上,这将阻止客户端调用该方法。第二部分:我希望这个方法不公开,否则 doxygen 会将其导出到文档中,从而使 API 的用户感到困惑。我给你投了赞成票
        【解决方案5】:

        我有几个解决方案,所有解决方案都围绕使用私有单例实例作为“密钥”来证明调用者就是他们所说的那个人。

        解决方案1:朋友类是单例

        public class A
        {
          private underwear myUnderwear;
        
          public ChangeUnderwear(B friend, underwear newUnderwear) 
          {
            if (friend == null) return;
            myUnderwear = newUnderwear
          }
        }
        
        public sealed class B
        {
          private B() {};
          private B inst;
          private MessWithA(A a)
          {
            a.ChangeUnderwear(this, new Thong());
          }
        }
        

        有人看到那里有任何缺陷吗?当你有一个 Foo 类和一个 FooManager 单例时,这种技术会起作用。

        解决方案 2: 如果朋友不是单例,我想你可以使用隐藏构造和隐藏所有实例的相同想法:

        interface IB
        { ... }
        
        public sealed class B : IB
        {
          private B() {};
          public IB CreateB()
          {
            return (IB)new B();
          }
          private MessWithA(A a)
          {
            a.ChangeUnderwear(this, new Thong());
          }
        }
        

        但是现在您需要某种方法来防止敌人简单地将 IB 转换为 B,然后冒充 B 访问 A 的仅限朋友的成员。有什么想法吗?

        解决方案 3:单例类让它的实例由第一个请求它的调用者拥有。朋友类试图在启动时抓取实例,如果其他人先抓取它就会发脾气

        public class A
        {
          private underwear myUnderwear;
        
          public ChangeUnderwear(B.IdCard friend, underwear newUnderwear) 
          {
            if (friend == null) return;
            myUnderwear = newUnderwear
          }
        }
        
        public class B
        {
          public sealed class IdCard
          {
            private IdCard() {};
            private static bool created = false;
            public IDCard GetId()
            {
              if (created) throw new Exception("Why are two people asking for the same ID?!?");
              created = true;
              return new IDCard();
            }
          }
        
          private static IdCard id;
        
          static B()
          {
            id = IDCard.CreateId();
            if (id == false) throw new Tantrum("Panic: Someone stole my ID card before I could grab it");
          }
        
          private void MessWithA(A a)
          {
            a.ChangeUnderwear(id, new Thong());
          }
        }
        

        【讨论】:

          猜你喜欢
          • 2010-10-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-09-24
          • 1970-01-01
          • 1970-01-01
          • 2010-11-11
          相关资源
          最近更新 更多