【问题标题】:Restricting class method access to one other class限制对另一个类的类方法访问
【发布时间】:2011-05-09 09:35:39
【问题描述】:

您好。

我有两个类,“数据库”和“组”。我希望能够创建“组”的实例并从“数据库”中调用这些实例的方法,并能够公开分发“组”实例引用。但是,我不想提供对“组”中的构造函数或其他方法的公共访问。

我最初认为我可以通过将“组”设为“数据库”的私有内部类来实现此访问限制,但我发现如果它是私有的,我无法公开分发对“组”的引用。另外,我尝试将“Group”设为公共内部类失败了,因为如果它的方法都是私有的,“Database”就无法访问它们,而如果它们是公共的,则可以在“Database”之外访问。

我正在寻找解决或规避此问题的最佳实践技术。也许我错过了某个地方的必要关键字?到目前为止,我在研究中没有发现任何东西表明 C# 允许这种控制粒度。正如我在下面的代码中提供的那样,我找到了一种解决问题的混乱方法。它的本质是:在“数据库”中的每次调用“组”中的方法之前,在“数据库”中设置一个公开可读但只能私有设置的字段,“组”的方法都检查它们创建的“实例”数据库”在执行其预期操作之前。读取字段时(通过“数据库”中的公共方法),该字段会被重置,从而阻止对“组”的任何进一步方法调用,直到“数据库”再次设置该字段。

public class Database {

    // Field; true if Database has just authorized a method call to a %Group.
    private bool group_isNextCallAuthorized = false;

    // Invoked before every method call to a %Group.
    private void Group_AuthorizeNextCall() {
        group_isNextCallAuthorized = true;
 }

    // Method, ordinarily called from %Group, that checks its creating %Database
    //  that the %Database itself authorized the method call on the %Group. It
    //  automatically resets the authorization to false to prepare for the next,
    //  perhaps unauthorized, method call.
    public bool Group_IsNextCallAuthorized() {
        bool previousValue = group_isNextCallAuthorized;
        group_isNextCallAuthorized = false;
        return previousValue;
    }

    // Constructor; creates a demo %Group.
    public Database() {

        // Create a %Group, first authorizing the action.
        Group_AuthorizeNextCall();
        Group group = Group.Create(this);

        // Call some method on the group
        Group_AuthorizeNextCall();
        group.SomeGroupMethod();

    }

}

public class Group {

    // Field; refers to the %Database that created this %Group instance.
    private Database db;

    // Generates an instance of %Group, requiring the creating %Database as an
    //  argument. After checking that the %Database %db isn't null, it verifies
    //  that %db actually requests and authorized this %Group's creation via the
    //  %Group_IsNextCallAuthorized(.) method provided by %Database.
    public static Group Create(Database db) {

        // It will not create a dud instance of %Group; it will throw an exception
        //  instead.
        if ((db == null) || !db.Group_IsNextCallAuthorized())
            throw new System.Exception("Unauthorized access.");

        return new Group(db);
    }

    // This constructor is referenced internally by static %Create(.) as above.
    private Group(Database db) {
        this.db = db;
    }

    // This is an arbitrary method showing that it must check that the %Database
    //  that created this %Group authorized this method call before it will
    //  perform its intended function.
    public void SomeGroupMethod() {
        if (!db.Group_IsNextCallAuthorized())
            throw new System.Exception("Unauthorized access.");

        // intended functionality...
    }

}

【问题讨论】:

    标签: c# access-modifiers restriction


    【解决方案1】:

    要使用 C# 访问规则表达这种可见性,您需要反转类嵌套:使 Database 成为 Group 内的嵌套类,以便它可以访问 Group 的私有位。

    【讨论】:

    • 我认为您的方法适用于我所描述的问题。但是,我实际上希望能够扩展此代码以允许也以相同的方式从“数据库”创建另一个类似于“组”的类,并具有相同的访问限制。对我来说,你的方法是否可以适应这个问题的变化并不明显。
    • 在这种情况下,您唯一的选择是使用internal 而不是private,因为CLR 没有朋友类的概念。您可能需要将此对象模型设为自己的程序集,以区分internal 的扩展范围。
    【解决方案2】:

    您可以使用嵌套类方法。可能不是紧耦合以来最优雅的一个,但会成功。

     public class DataBase 
     {
          private class Group 
          {
                private Group() {} 
    
          }
    
          private Group group = null;
    
          public DataBase() 
          {
             this.group = new Group();
          }
    
          public Group 
          {
             get 
             {
                return this.group;
    
             }   
     }
    

    【讨论】:

    • 这不会编译。
    【解决方案3】:

    一种选择是将接口 IGroup 公开给代码的外部部分。这个接口只有属性的getter,你想要访问的任何方法等。然后数据库将对Group类进行操作,拥有对所有属性/方法的完全访问权限,并返回IGroup

    【讨论】:

    • 这在我看来确实是个好主意。但是,当我想从“数据库”外部使用“组”作为“数据库”方法的参数时,它似乎确实削弱了自动类型检查,因为我必须传递一个可以实现的“IGroup”任何班级。尽管如此,由于无论如何我都可以在“数据库”中手动验证类型,因此这种技术看起来可以大大降低我的代码复杂性。
    猜你喜欢
    • 2012-02-15
    • 2022-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-27
    • 2014-10-04
    • 2017-01-03
    相关资源
    最近更新 更多