limit method to only be called by a particular class
我希望一个类中的特定方法只能由特定的类访问。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 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()不能使用。我相信乔恩·斯基特的回答,我所要求的不能用C语言完成。
这个问题和乔恩的回答对那些稍后可能遇到这个问题的人来说是好的。事实上,这种设计的气味可能会让任何人选择像这样的东西作为理想的解决方案。
正如在评论中提到的,如果你试图解决类似的情况,c朋友的对话是有用的阅读。
至于我的特定解决方案:"为什么a包含b的逻辑"(由@sysexpand在注释中提出)。这就是问题所在。我正在研究的整个系统中都调用了B.Func(),但它主要是在一个单独的A上运行的。所以我最后做的是把B的Func()转移到A中,使A.LimitedAccess()私有化。还有一些其他的细节需要解决,就像以前一样,但是我得到了一个低影响的解决方案,它给了我在A.LimitedAccess()的调用者上的编译时错误。
谢谢你的讨论。
- 你为什么要这样做?
- 我有一个大类A,在整个系统中广泛使用。类B具有其他依赖项,但具有使用b.limitedaccess()的标准/最佳方法。我想尽可能强制使用B.Func()。
- 请参阅stackoverflow.com/questions/203616/…您应该将LimitedAccess标记为内部的,并通过代码检查发现它被滥用。
- @施利茨,恐怕你的代码中有某种设计缺陷,我想不出有必要这样做的单一情况。你介意分享你的一些实际代码吗?
- 脏选项是从a继承b并使limitedaccess受保护。如果它在语义上没有意义,不要。
- @MarkusMeskanen——是的,当然有一个设计缺陷。但我现在不能进行大范围的重新设计。我必须采取低影响的方法。
- @不是的,我编辑了你的报价,所以它揭示了你在这里遇到的实际问题。你不应该做你想做的事。如果你真的需要去做,就不要去做。换点别的东西,这样你就不再需要去做了。老实说,如果你要这样做,你就是顽固和无知。
- @MarkusMeskanen不需要叫名字。乔斯,你应该把你在评论中发表的澄清(需要低影响的方法,不能重新设计项目,"为什么")作为警告放到问题中。他们不会做任何长期的好事作为评论。
- @乔治斯托克不会收回我的话,但我道歉。我应该把我的话考虑得更好。:)
- 在使用存储库模式的项目中,需要这样做的一个很好的例子。您的聚合可能具有只能由存储库类访问的方法。换句话说,例如,只有从存储库接口继承的类才能直接添加子级。我知道还有其他的解决方案,但它们似乎都包括一些诸如允许私人成员访问的内容。
不,您唯一能做的就是使LimitedAccess成为私有方法,并将类B嵌套在类A中。
(我假设您希望所有类都在同一程序集中。否则,可以把A和B放在同一个组件中,把C放在不同的组件中,使LimitedAccess成为internal方法。)
- 实际上还有另一个方法,但这要求特定的类创建对象,创建的类将接口实现公开为out方法(new A(out limitedAccessMethods))。当然,这需要A中的私有嵌套类,该类实现接口,但只允许通过创建类访问。然而,从设计的角度来看,它是否好还是值得怀疑的。当然,这是有限的。
假设您只想限制对特定实例的方法和变量的访问,那么可以通过使用接口来实现这种效果。但是,它不会阻止某人创建自己的类实例,此时他们将拥有对该实例的完全访问权。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| 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();
}
} |
也许这是一个解决办法。
使用system.runtime.compilerservices,然后可以检查调用函数的名称和/或定义调用函数的文件。如果每个文件都有一个类,则文件名可能是类名的替换项。检查并阻止呼叫。
1 2 3 4 5 6 7 8
| 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
} |
这样的设计不符合OOP最佳实践。不应保护类的方法不被调用。
如果您的设计需要对调用方法进行控制,那么应该通过测试参数来进行控制-授权进行调用的调用方将"知道"要作为参数传递的魔力词。
- 乔恩提供了两种完全合适的方法。另一方面,你的方法绝对是错误的。您没有任何编译时支持,它很容易被分解或通过使用反编译程序破解,现在类的用户有一个令人困惑的API方法来查看他们不应该实际使用的方法。
- 问题是:"我希望一个类中的一个特定方法只能由一个特定的类访问。"您只是不要尝试这样做…另一件事是声明一个方法内部,然后从程序集中的所有类访问它。但这不是问题。
- 这并不能解决这个问题;这个方法仍然可以在任何地方访问,如果没有正确的魔法参数,它就不能在任何地方正常工作。Jon的两个解决方案实际上都涉及到从那些不应该访问的方法限制方法的可访问性。
- 你错过了要点。编译器只能测试方法可见性,但方法可见性是通用的——它要么对其他类可见,要么不可见。一个班是看不见的。Yaur做的对——如果您认为方法是从代码中不正确的位置调用的,请进行代码检查。如果你不同意,请提出解决方案…您可以尝试使用嵌套类等,但这只是在逃避核心问题——而问题是糟糕的设计。
- 我已经说过两次了,乔恩提供了两种可行的解决方案。如果真的只应从另一个类调用方法,那么另一个类很可能是一个嵌套类,这将允许这种精确的行为。根据上下文的不同,它也可能只适合内部使用;通过internal公开类型功能的扩展部分,而将其他部分作为public公开是一种常见的技术。
- 带有公共方法的私有嵌套类只是私有方法。内部不保存从许多类调用的方法。如果您希望只从一个类中调用一个方法,那么将它放入该类中并使其成为私有的!示例具有误导性—它创建新的a只是为了调用其方法—如果您有实例,那么调用该方法,为什么是间接的?还有一些只有B知道的东西,那应该是一个外部依赖,并传递给A。只有B知道如何使它成为"某物",这就是解决方案——超越编译器的能力,而是一个适当的OOP设计。
- 显然,您不理解如何使用嵌套类来实现这一点。当然可以。在这个例子中,public class A{private void Foo(){} public class B{ private void Bar(){new A().Foo();}}B是一个可以访问A的私有Foo方法的公共类,但它是唯一可以这样做的其他类,这正是OP所要求的。至于内部,这是一个解决方案,从技术上来说,这不是OP要求的,但可能能够解决OP的问题。如果这不是一个选项,那么他将需要依赖于嵌套类型。
- 您的代码使a.foo()成为公共类b的私有方法。这正是我所说的。这是一个糟糕的设计,因为整个过程都围绕着某个由B提供并要求A操作的秘密对象——否则为什么会这样?明天,将有一个C级,它有不同的秘密成分。在那个时候,很明显这是一个糟糕的设计,因为A现在将有两个嵌套类。两天后-三个嵌套类,等等。还有奖金问题——为什么A会包含B的逻辑?这违反了良好设计的原则。
- 您假设Foo从未在A中调用,或者它不访问A的任何私有实例数据。在我的简单例子中没有,但它可以。这就是它不同于B中的私有方法的原因。没有说明,永远不会有其他类也需要访问数据。这不是你应该经常做的事情,但这和说永远不应该做的不同。是的,这意味着A和B是紧密耦合的。事实上,它们被嵌套的事实清楚地表明了这一点。有时候这是合适的。
- "为什么a会包含b的逻辑"——这就是难点。在我工作的整个系统中都调用了b.func(),但它主要是在单个a上操作的。因此,我最终将b.func()移动到a中并使a.limitedaccess()私有。还有一些其他的细节需要解决,就像以前一样,但是我得到了一个低影响的解决方案,它给了我在a.limitedaccess()调用程序上的编译时错误。谢谢你的讨论。即使设计不好,最初的问题在理论上也是有趣的。
- 伙计们,感谢有机会深入讨论这个问题。我肯定会继续考虑这种编码模式。