using System;
public interface IFriendKey { object Id {get; set;} }
class Friend<TFriend>
{
protected void FriendAssert(IFriendKey key)
{
if ( key == null || key.Id == null || key.Id.GetType() != typeof(TFriend) )
throw new Exception("No right to execute the called method.");
}
}
class A : Friend<B>
{
public void f(IFriendKey key)
{
FriendAssert(key);
Console.WriteLine("ONLY class B can execute this method successfully, even though it is declared public.");
}
}
class B
{
private class AFriendKey : IFriendKey
{
public object Id {get; set;}
}
IFriendKey Key { get { return new AFriendKey() {Id = this}; } }
public void g()
{
new A().f(this.Key);
}
}
public class Test
{
public static void Main()
{
new B().g();
}
}
dXNpbmcgU3lzdGVtOwoKcHVibGljIGludGVyZmFjZSBJRnJpZW5kS2V5IHsgb2JqZWN0IElkIHtnZXQ7IHNldDt9IH0KCmNsYXNzIEZyaWVuZDxURnJpZW5kPgp7Cglwcm90ZWN0ZWQgdm9pZCBGcmllbmRBc3NlcnQoSUZyaWVuZEtleSBrZXkpCgl7CgkJaWYgKCBrZXkgPT0gbnVsbCB8fCBrZXkuSWQgPT0gbnVsbCB8fCBrZXkuSWQuR2V0VHlwZSgpICE9IHR5cGVvZihURnJpZW5kKSApCgkJCXRocm93IG5ldyBFeGNlcHRpb24oIk5vIHJpZ2h0IHRvIGV4ZWN1dGUgdGhlIGNhbGxlZCBtZXRob2QuIik7Cgl9Cn0KCmNsYXNzIEEgOiBGcmllbmQ8Qj4KewoJcHVibGljIHZvaWQgZihJRnJpZW5kS2V5IGtleSkKCXsKCQlGcmllbmRBc3NlcnQoa2V5KTsKCQlDb25zb2xlLldyaXRlTGluZSgiT05MWSBjbGFzcyBCIGNhbiBleGVjdXRlIHRoaXMgbWV0aG9kIHN1Y2Nlc3NmdWxseSwgZXZlbiB0aG91Z2ggaXQgaXMgZGVjbGFyZWQgcHVibGljLiIpOwoJfQp9CgpjbGFzcyBCCnsKCXByaXZhdGUgY2xhc3MgQUZyaWVuZEtleSA6IElGcmllbmRLZXkgCgl7CgkJcHVibGljIG9iamVjdCBJZCB7Z2V0OyBzZXQ7fQoJfQoJCglJRnJpZW5kS2V5IEtleSB7IGdldCB7IHJldHVybiBuZXcgQUZyaWVuZEtleSgpIHtJZCA9IHRoaXN9OyB9IH0KCQoJcHVibGljIHZvaWQgZygpCgl7CgkJbmV3IEEoKS5mKHRoaXMuS2V5KTsKCX0KfQoKcHVibGljIGNsYXNzIFRlc3QKewoJcHVibGljIHN0YXRpYyB2b2lkIE1haW4oKQoJewoJCW5ldyBCKCkuZygpOwoJfQp9