c# - 如何允许特定的类调用特定方法

时间:2018-02-16 23:55:28

标签: c# class methods

在我的代码中,我只需要允许来自类 MainData 的类 EchoProcess 调用方法 GetStorePrivateData 。我认为这不是更好的方法,但在此代码工作完成。我该怎么办?

**在以后的课程中, MainData 会有更多受保护的类,并允许其他类调用它。

// namespace and use statements...

class ProcessMessages implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $data;

    public function __construct(array $data)
    {
        $this->data = $data;
    }

    public function handle()
    {
        $token = $this->data['token'];
        // ...
    }
}

2 个答案:

答案 0 :(得分:3)

  

在我的代码中,我只需要允许来自类EchoProcess的类GetStorePrivateData调用方法MainData

请勿使用反射或堆叠痕迹执行任何此类操作

这两种类型都是internal。他们在同一个集会中。将您希望限制来电者的方法标记为internal。现在程序集中的任何代码都可以调用该方法。 谁在乎?你写了那段代码;如果你不喜欢它,你可以改变它。

这是一个问题,应该通过与正在编写程序集的编码人员进行通信来解决使用程序集实现细节的正确协议。这是一个人际关系团队关系问题,所以不要试图通过编写代码来解决它。将该方法标记为内部,如果您不喜欢的网站,则与在代码审核期间编写该网站的开发人员交谈,以找出他们认为这是一个好主意的原因。

答案 1 :(得分:0)

  

在以后的类中,MainData将拥有更多受保护的类,并允许特定的其他类来调用它。

很高兴听到它......我在下面提供的解决方案并不理想(例如,你不会在编译时遇到任何错误),而且有些对象模型可能更适合这种情况。

  

在我的代码中,我只需要允许来自类MainData的类EchoProcess调用方法GetStorePrivateData。我认为这不是更好的方法,但在这段代码中它完成了工作。我该怎么办?

编写检查调用堆栈的代码非常容易(您可以使用var s = new StackTrace()获取副本并使用s.GetFrames()遍历堆栈)。您可以遍历调用堆栈,查看调用者是EchoProcess还是来自其他地方。这是一个简单的例子:

static public class CallPermissionHelper
{
    static public bool IsAllowed<T>() where T : class
    {
        var callers = new StackTrace()
            .GetFrames()
            .Select
            (
                f => f.GetMethod().DeclaringType
            );
        var immediateCaller = callers.ElementAt(1);
        var firstOutsideCaller = callers
            .Skip(2)
            .Where
            (
                t => t != immediateCaller 
            )
            .FirstOrDefault();
        return (firstOutsideCaller == typeof(T));
    }
}

逻辑很简单:

  1. 获取从堆栈跟踪派生的调用者列表。
  2. 忽略第一帧(引用当前代码位置,不是很有帮助)
  3. 检查第二帧以确定调用我们的帮助程序类的类。在我们的例子中,它将是MainData。我们可以忽略这个类中的任何堆栈帧,例如如果它正在调用自己或使用实用程序函数,因为很明显它有权调用自己。
  4. 检查剩余的帧是否有任何其他类,在堆栈中工作。如果我们遇到的第一个类是EchoProcess,我们返回true。在所有其他情况下,我们返回false。
  5. 以下是如何在您的示例中使用它:

    internal sealed class EchoProcess : MainData
    {
        private class Key {}
    
        public static string GetPrivateFromMainData()
        {
            return MainData.GetStorePrivateData<EchoProcess, Key>();
        }
    }
    
    internal class MainData
    {
        public static string GetStorePrivateData<TEcho, TKey>() where TEcho : class where TKey : class
        {
            var allowed = CallPermissionHelper.IsAllowed<EchoProcess>();  //Magic!!!
            return allowed ? "Allowed" : "Blocked";
        }
    }
    
    public class Program
    {
        public static void Main()
        {
            var a = EchoProcess.GetPrivateFromMainData();
            var b = MainData.GetStorePrivateData<object, object>();
    
            Console.WriteLine("a={0}", a);
            Console.WriteLine("b={0}", b);
        }
    }
    

    输出:

    a=Allowed
    b=Blocked
    

    See my code on DotNetFiddle