我希望一个类中的特定方法只能由特定类访问。例如:
public class A
{
public void LimitedAccess() {}
public void FullAccess() {}
}
public class B
{
public void Func()
{
A a = new A();
a.LimitedAccess(); // want to be able to call this only from class B
}
}
public class C
{
public void Func()
{
A a = new A();
a.FullAccess(); // want to be able to call this method
a.LimitedAccess(); // but want this to fail compile
}
}
我是否可以使用关键字或属性来强制执行此操作?
更新
由于现有的系统复杂性和时间限制,我需要一个影响较小的解决方案。我想在编译时指出无法使用LimitedAccess()。我相信Jon Skeet的答案正是我所要求的不能用C#完成。
这个问题和Jon的回答对那些可能会遇到这个问题的人有好处。事实上,这种设计气味可以让任何人选择这样的东西作为理想的解决方案。
如评论中所述,如果您尝试解决类似情况,C# friend对话很有用。
至于我的特定解决方案:“为什么A会包含B的逻辑”(@sysexpand在评论中提到)。这就是问题所在。在我正在研究的整个系统中调用了B.Func()
,但它主要是在A
的单例上运行。所以我最终做的是将B
的{{1}}移到Func()
并将A
设为私有。还有其他一些细节可以解决,但总是如此,但是我得到了一个影响较小的解决方案,它给调用者A.LimitedAccess()
带来了编译时错误。
感谢您的讨论。
答案 0 :(得分:21)
没有。您唯一能做的就是让LimitedAccess
成为私有方法,并在类B
中嵌套类A
。
(我假设你想要同一个程序集中的所有类。否则你可以将A
和B
放在同一个程序集中,将C
放在不同的程序集中,将LimitedAccess
设为internal
方法。)
答案 1 :(得分:3)
假设您只想限制对特定实例的方法和变量的访问,您可以通过使用接口来实现此效果。但是,它不会阻止某人创建自己的类实例,此时他们将拥有对该实例的完全访问权。
public interface IA
{
void FullAccess();
}
public class A : IA
{
public void LimitedAccess() {} //does not implement any interface
public void FullAccess() {} //implements interface
}
public class B
{
private A a = new A();
public IA GetA()
{
return (IA)a;
}
public void Func()
{
/* will be able to call LimitedAccess only from class B,
as long as everybody else only has a reference to the interface (IA). */
a.LimitedAccess();
}
}
//This represents all other classes
public class C
{
public IA Ia;
public void Func()
{
Ia.FullAccess(); // will be able to call this method
Ia.LimitedAccess(); // this will fail compile
}
}
public static class MainClass
{
static void Main(string[] args)
{
B b = new B();
b.Func();
C c = new C();
c.Ia = b.GetA();
c.Func();
}
}
答案 2 :(得分:1)
也许这是一种解决方法。
使用System.Runtime.CompilerServices然后您可以检查调用函数的名称和/或定义调用函数的文件。如果每个文件都有一个类,则文件名可能是类名的替代。检查并阻止通话。
internal void MySecretFunction (string something,
[CallerMemberName] string memberName = null,
[CallerFilePath] string filePath = null,
[CallerLineNumber] int lineNumber = 0) {
if (!filePath.EndsWith(@"\goodClass.cs")) return;
// else do something
}
答案 3 :(得分:0)
制作此类设计是违反OOP最佳做法的。不应该保护类的方法不被调用。
如果你的设计需要控制调用方法,那么应该通过测试参数来进行控制 - 被授权进行调用的调用者将会知道"知道"作为论点传递的神奇词语。
答案 4 :(得分:0)
如果您只是想提醒自己(或队友)不要到处叫LimitedAccess
,则可以考虑使用显式接口实现或将LimitedAccess
标记为过时。
public interface IA
{
void LimitedAccess();
void FullAccess();
}
public class A : IA
{
private void LimitedAccess() { }
public void FullAccess() { }
void IA.LimitedAccess() => LimitedAccess();
void IA.FullAccess() => FullAccess();
}
public class B
{
public void Func()
{
IA a = new A();
a.LimitedAccess(); // want to be able to call this only from class B
}
}
public class C
{
public void Func()
{
A a = new A();
a.FullAccess(); // want to be able to call this method
a.LimitedAccess(); // -> fails to compile
}
}
答案 5 :(得分:0)
您总是可以通过 StackTrace 看到调用类型。 请注意,在发布模式下构建时,对堆栈的调用将得到优化,并且堆栈跟踪可能返回一个完全不同的类,因此请确保在发布前对其进行测试。
/// <summary>
/// Warning: Any class that calls this other than "B" will throw an exception.
/// </summary>
public void LimitedAccess()
{
if (new System.Diagnostics.StackTrace().GetFrame(1).GetMethod().DeclaringType != typeof(B)) throw new Exception("Invalid Caller Type, B is only class able to call this method.");
}
不幸的是,您将无法知道它是否在编译时出错。你能做的最好的事情就是在它被调用时抛出一个异常,并添加一条评论警告人们。
答案 6 :(得分:0)
这是@cowlinator 建议的解决方案的变体,使用派生自类 AWithUnlimitedAccess
的类 A
而不是实现接口 A
的类 IA
。
结果和限制是一样的,但我更喜欢它,因为 (1) 受限访问方法是在它自己的类中定义的,并且 (2) 添加文档注释更容易。
public class A
{
public void FullAccess() { }
}
public class AWithUnlimitedAccess : A
{
public void LimitedAccess() { }
}
public class B
{
private AWithUnlimitedAccess a = new AWithUnlimitedAccess();
public A GetA()
{
return a;
}
public void Func()
{
a.FullAccess();
a.LimitedAccess();
}
}
// This represents all other classes
public class C
{
public A A;
public void Func()
{
A.FullAccess();
A.LimitedAccess(); // this will fail compile
}
}
public static class MainClass
{
static void Main(string[] args)
{
B b = new B();
b.Func();
C c = new C();
c.A = b.GetA();
c.Func();
}
}