limit方法只能由特定类调用

时间:2013-05-15 18:55:24

标签: c#

我希望一个类中的特定方法只能由特定类访问。例如:

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()带来了编译时错误。

感谢您的讨论。

7 个答案:

答案 0 :(得分:21)

没有。您唯一能做的就是让LimitedAccess成为私有方法,并在类B中嵌套类A

(我假设你想要同一个程序集中的所有类。否则你可以将AB放在同一个程序集中,将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();
    }
}