好吧,让我们离开关于友谊是否打破封装的辩论,并且实际上尝试优雅地提出一个连贯的设计。这是一个双重功能:
1)关于如何实施的一般性问题:
public class A
{
friend class B;
}
2)为什么我需要这个功能?我的一些类实现了ISerializable
接口。但是,我想在Derived类中保护ISerializable
个方法,这样我就不会将它们暴露给客户端(以及文档中)。但是,内部类应该能够访问它们。在C#中解决这个问题的一般方法是什么?
注意:我正在使用当前C ++标准中定义的友谊。
由于
答案 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());
}
}