在C#中实现好友(C ++中提供)功能

时间:2009-03-04 22:26:56

标签: c# .net c++ serialization

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

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

  public class A 
   {
      friend class B;
   }


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

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

由于

5 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:4)

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

答案 2 :(得分:1)

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

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

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

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

解决方案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());
  }
}