我知道有一个'内部' keyword和[InternalsVisibleTo]属性。但是如何允许不在同一程序集中的类级别的类来修改私有数据呢?也就是说,只允许程序集中的特定类访问私有数据,而不允许该程序集下的evey类?
我在此之前问过这个问题How to implement C++ like friend relationship in C#但是它不够具体,所以我在这里再问一遍。
此处讨论了与C#不使用朋友的理论和原因相关的其他讨论 Why does C# not provide the C++ style 'friend' keyword?
答案 0 :(得分:0)
我已经考虑过了,我认为我有一个反思的解决方案。不确定这是一个很好的方法。
如果我有SomeClass有朋友FriendClass。 NotFriendClass和FriendClass在同一个程序集中,但只有FriendClass可以访问SomeClass的私有数据。以下是SomeClass的需求:
class SomeClass
{
private bool isMyFriend()
{
StackTrace st = new StackTrace();
StackFrame callerSF = st.GetFrame(2);
MethodBase mb = callerSF.GetMethod();
Type callerType = mb.DeclaringType;
// FriendClass is my friend
if (typeof(FriendClass) == callerType)
return true;
else
return false;
}
// ....
在这个方法中,SomeClass检查调用者类是否是他的朋友。是的,它有一个硬编码的if(typeof(FriendClass)== callerType)但是C ++的朋友也需要在声明中对类名进行硬编码。
对于那些"知道朋友" SomeClass的方法,应该是:
public bool SetData(int x)
{
if (!isMyFriend())
return false;
this.privateData = x;
return true;
}
唯一的问题是运行时检查。但是,我认为使用friend将一些程序从C ++移植到C#已经足够了。
答案 1 :(得分:0)
我通常会将一个友好关键字似乎很方便的情况转换为一种模式,其中一个类本身确定哪些类可以实例化它,而不会破坏正确的OO设计。
想法是希望控制谁可以实例化的类,为允许获取它的实例的类提供友谊。例如,InControl类允许ChosenOne和ChosenTwo类获取InControl的实例。
“选择”类(即ChosenOne或ChosenTwo)可以“参与”InControl提供的友谊与其自身的实例(friendship.engage(this)),而友谊可以通过提供它来“接受”该实例InControl的一个实例(friend.accept(new InControl()))。
实际的友谊是通过嵌套的单个实例友谊类实现的。友谊仅限于使用通用IFriendship接口的“选定”类,其中T是选定的类。反过来,每个'选择'类需要实现通用的IFriendable接口,其中T为InControl,以便能够接收InControl的实例。
InControl类有一个私有构造函数,以避免除了朋友之外的任何人进行实例化:
public interface IFriendable<T>
{
void accept(T friend);
}
public interface IFriendship<T>
{
void engage(T friend);
}
public class ChosenOne : IFriendable<InControl>
{
private InControl _friend { get; set; }
private ChosenOne()
{
InControl.friendship.engage(this);
}
public void accept(InControl friend)
{
_friend = friend;
}
}
public class ChosenTwo : IFriendable<InControl>
{
private InControl _friend { get; set; }
private ChosenTwo()
{
InControl.friendship.engage(this);
}
public void accept(InControl friend)
{
_friend = friend;
}
}
public class InControl
{
public interface IFriendship : IFriendship<ChosenOne>, IFriendship<ChosenTwo> { }
public static IFriendship friendship { get { return Friendship.instance; } }
private class Friendship : IFriendship
{
static Friendship()
{
}
internal static readonly Friendship instance = new Friendship();
public void engage(ChosenOne friend)
{
friend.accept(new InControl());
}
public void engage(ChosenTwo friend)
{
friend.accept(new InControl());
}
}
private InControl()
{
}
}