29

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

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# 中完成。

这个问题和乔恩的回答对于以后可能遇到这个问题的人来说是很好的。这种设计气味的事实有望使任何人远离选择这样的东西作为所需的解决方案。

正如评论中提到的,如果您试图解决类似的情况, C# 朋友对话非常有用。

至于我的特殊解决方案:“为什么 A 会包含 B 的逻辑”(@sysexpand 在评论中询问)。这就是问题所在。 B.Func()在我正在处理的整个系统中都被调用,但它主要在A. 所以我最终做B的就是Func()搬进AA.LimitedAccess()私有化。与往常一样,还有一些其他细节需要解决,但我得到了一个影响较小的解决方案,它给我的调用者带来了编译时错误A.LimitedAccess()

感谢您的讨论。

4

7 回答 7

25

不,您唯一能做的就是创建LimitedAccess一个私有方法,并将类嵌套B在 classA中。

(我假设您希望所有类都在同一个程序集中。否则,您可以将AandB放在同一个程序集中,C在不同的程序集中,然后创建LimitedAccess一个internal方法。)

于 2013-05-15T18:56:34.890 回答
6

是的。你所要求的完全有可能。

您可以通过使用接口来限制对特定实例的方法和变量的访问。

但是,单独的接口不能阻止某人创建自己的类实例,此时他们将拥有对该实例的完全访问权限。

为此,接下来您应该将其作为私有类嵌套在另一个类中,以限制对构造函数的访问。

现在,您在一个类中有一个特定方法,只能由特定类访问。

在这个例子中,只有 classB能够访问 function LimitedAccess

public interface IA
{
  void FullAccess();
}

public class B
{
  private class A : IA
  {
    public void LimitedAccess() {}  //does not implement any interface
    public void FullAccess() {}     //implements interface
  } 
    
  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 void Func(IA ia)
  {
     ia.FullAccess();           // will be able to call this method
     ia.LimitedAccess();        // this will fail to compile
  }
} 

public static class MainClass
{
  public static void Main(string[] args)
  {
    B b = new B();
    b.Func();
          
    IA ia = b.GetA();
      
    C c = new C();
    c.Func(ia);
  }
}
于 2016-02-29T22:52:19.740 回答
2

如果您只是想提醒自己(或队友)不要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
    }
}
于 2019-05-21T06:45:14.147 回答
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
}
于 2017-10-21T20:27:59.453 回答
0

进行这样的设计是违反 OOP 最佳实践的。不应该保护类的方法不被调用。

如果您的设计需要控制调用方法,则应通过测试参数来进行控制 - 被授权进行调用的调用者将“知道”作为参数传递的魔法词。

于 2013-05-15T20:05:26.500 回答
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.");
}

不幸的是,您将无法知道它是否在编译时出现错误。你能做的最好的就是在它被调用时抛出一个异常,并添加一条评论警告人们。

于 2021-02-20T04:08:36.747 回答
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();
    }
}
于 2021-07-27T22:34:33.037 回答