C#中的封装和友谊
本文关键字:友谊 封装 | 更新日期: 2023-09-27 17:53:48
我在当前项目中有一个特殊的案例。
我有:
public class A
{
// etc.
}
public class B
{
// etc.
private void HandleSomeEvent(object parameter)
{
// Etc.
}
protected void HandleSomeOtherEvent(object parameter)
{
// Etc.
}
}
我想要:
A
能够调用私有方法B.HandleSomeEvent
,但没有其他类(除了B
(能够这样做A
能够调用受保护的方法B.HandleSomeOtherEvent
,但没有其他类(除了B
和B
的派生类(能够这样做
这在C#中可能吗?
- 如果可能,如何做到这一点
- 如果不可能,有什么替代方案可以尽可能保护
B
不被同一程序集中的类C
篡改
这在C#中可能吗?
不可以,除非您使用反射:私有成员和受保护成员不能从其他类访问。
如果不可能,有什么替代方案可以尽可能保护B免受同一程序集中的C类的篡改?
您可以将B设为a内部的嵌套类,并将其设为私有类。然后,您可以安全地增加B的两个方法的可见性,因为只有A能够调用它们(除非使用反射(。
这是可能的,但我通常只使用internal
,并假设程序集中的其他类表现良好。
例如,您可以将这些方法的委托传递给类A,该类将它们存储在protected static
字段/属性中。
"2。如果不可能,有什么替代方案可以尽可能保护B免受同一程序集中的C类的篡改?">
检查调用者的类型信息并抛出异常是否有效?
[MethodImpl(MethodImplOptions.NoInlining)]
private void HandleSomeEvent(object parameter)
{
StackTrace stackTrace = new StackTrace();
StackFrame stackFrame = stackTrace.GetFrame(1);
MethodBase methodBase = stackFrame.GetMethod();
if(methodBase.DeclaringType == typeof(ClassA)) // Okay.
else if (methodBase.DeclaringType == typeof(ClassB)) // Okay.
else throw new ApplicationException("Not Okay");
}
可以通过发出A的接口,然后将其与具体实现分离。一旦你做到了,你就可以写这样的
interface IA { }
class A : IA
{
public static IA New() { return new A(); }
private A() { }
private void UseB()
{
var b = new B();
b.HandleSomeEvent(this, null);
}
}
class B
{
public void HandleSomeEvent(A onlyAccess, object parameter) { }
}
尽管HandleSomeEvent()
是公共的,但只有A可以访问它,因为其他人不可能获得A类的具体实例。它有一个私有构造函数,而工厂New()
方法返回一个接口。
请参阅我的文章《Friends and internal interface members with coding to interfaces》,了解详细信息。
您可以将两种方法都标记为internal
:
internal void HandleSomeEvent(object parameter)
{
// Etc.
}
protected internal void HandleSomeOtherEvent(object parameter)
{
// Etc.
}
这使得这两个方法对同一程序集中的所有类都可见(第二个方法对从B
派生的所有类也可见(。
没有办法使方法对特定的其他类可见。毕竟,您是控制程序集中所有类的人,所以您应该确保除了A
之外没有其他类调用这些方法。
如果你真的需要工具的帮助,你可以编写一个FxCop规则,或者创建某种后构建的操作,检查来自A
以外的其他类的方法调用。
- 不,它不是(除非你使用反射,但这只是糟糕的设计(
- 继承。但即便如此,您也无法调用私有方法。你应该考虑一下你的设计并加以改进
由于你的类A
应该能够在B
上调用protected
方法,我认为它与之有某种关系。问问自己是否存在"is-a"关系,比如"a是B"。在这种情况下,您可以使A
继承自B
:
public class A : B
{
}
现在,您可以在B
上调用受保护的方法。但请不要只是继承,要经常问问自己继承是否有意义。