您可以使用下面显示的技巧在 Bob 上创建一个FriendRecieveMessageFromAlice只能由 调用的方法Alice。一个邪恶的类,Eve如果不对私有成员使用反射,就无法调用该方法。
我很想知道其他人之前是否建议过这个或其他解决方案。几个月来,我一直在寻找解决该问题的方法,但我从未见过friend在不使用反射的情况下确保真正语义的解决方案(您几乎可以用它规避任何事情)。
爱丽丝和鲍勃
public interface IKey { }
public class Alice
{
// Alice, Bob and Carol must only have private constructors, so only nested classes can subclass them.
private Alice() { }
public static Alice Create() { return new Alice(); }
private class AlicePrivateKey : Alice, IKey { }
public void PublicSendMessageToBob() {
Bob.Create().FriendRecieveMessageFromAlice<AlicePrivateKey>(42);
}
public void FriendRecieveMessageFromBob<TKey>(int message) where TKey : Bob, IKey {
System.Console.WriteLine("Alice: I recieved message {0} from my friend Bob.", message);
}
}
public class Bob
{
private Bob() { }
public static Bob Create() { return new Bob(); }
private class BobPrivateKey : Bob, IKey { }
public void PublicSendMessageToAlice() {
Alice.Create().FriendRecieveMessageFromBob<BobPrivateKey>(1337);
}
public void FriendRecieveMessageFromAlice<TKey>(int message) where TKey : Alice, IKey {
System.Console.WriteLine("Bob: I recieved message {0} from my friend Alice.", message);
}
}
class Program
{
static void Main(string[] args) {
Alice.Create().PublicSendMessageToBob();
Bob.Create().PublicSendMessageToAlice();
}
}
前夕
public class Eve
{
// Eve can't write that, it won't compile:
// 'Alice.Alice()' is inaccessible due to its protection level
private class EvePrivateKey : Alice, IKey { }
public void PublicSendMesssageToBob() {
// Eve can't write that either:
// 'Alice.AlicePrivateKey' is inaccessible due to its protection level
Bob.Create().FriendRecieveMessageFromAlice<Alice.AlicePrivateKey>(42);
}
}
这个怎么运作
诀窍是该方法Bob.FriendRecieveMessageFromAlice需要一个(虚拟)泛型类型参数作为标记。该泛型类型必须继承自两者Alice,并继承自一个虚拟接口IKey。
由于Alice没有实现IKey自己,调用者需要提供一些子类,Alice它确实实现了IKey。但是,Alice只有私有构造函数,所以它只能被嵌套类子类化,而不能被其他地方声明的类子类化。
这意味着只有嵌套的类Alice可以子类化它来实现IKey。就是AlicePrivateKey这样,由于它被声明为私有,只能Alice将它作为通用参数传递给Bob.FriendRecieveMessageFromAlice,因此只能Alice调用该方法。
然后我们反过来做同样的事情,这样只有Bobcall Alice.FriendRecieveMessageFromBob。
泄露钥匙
值得注意的是,当被调用时,Bob.FriendRecieveMessageFromAlice它可以访问TKey泛型类型参数,并且可以使用它来欺骗来自Alice另一个OtherClass.OtherMethod<OtherTkey>接受OtherTKey : Alice, IKey. 因此,让密钥从不同的接口继承会更安全:Alice, IBobKey第一个接口和Alice, IOtherKey第二个接口。
比 C++ 朋友好
- 连
Bob自己也不能调用自己的方法Bob.FriendRecieveMessageFromAlice。
Bob 可以有多个朋友,使用不同的朋友方法:
// Can only be called by Alice, not by Carol or Bob itself
Bob.FriendRecieveMessageFromAlice <TKey>(int message) where TKey : Alice, IKey { }
// Can only be called by Carol, not by Alice or Bob itself
Bob.FriendRecieveMessageFromCarol <TKey>(int message) where TKey : Carol, IKey { }
我很想知道是否有某种方法可以比蛮力试错更有效地找到这样的技巧。某种“C# 类型系统的代数”,它告诉我们哪些限制可以强制执行,哪些不能,但我还没有看到任何关于此类主题的讨论。