2010-11-13 2 views
2

Приветствия.Ограничение доступа метода класса к одному другому классу

У меня есть два класса: «База данных» и «Группа». Я хочу иметь возможность создавать экземпляры «Групп» и методы вызова для этих экземпляров из «базы данных» и иметь возможность публично распространять ссылки на экземпляры «Группы». Однако я не хочу предоставлять публичный доступ к конструктору или другим методам в «Группе».

Первоначально предполагалось, что я могу достичь этого ограничения доступа, сделав «Группу» частным внутренним классом «База данных», но я обнаружил, что я не мог публично распространять ссылки на «Группу», если он был закрытым. Кроме того, мои попытки сделать «Группу» публичным внутренним классом не удались, потому что, если его методы были частными, «База данных» не могла получить к ним доступ, и если они были общедоступными, доступ был возможен за пределами «Базы данных».

Я ищу оптимальную технику для решения или обхода этой проблемы. Возможно, я где-то пропустил необходимое ключевое слово? Ничто из того, что я нашел до сих пор в моих исследованиях, не показало, что C# допускает эту гранулярность контроля. Я нашел грязный способ обойти проблему, как я уже приводил ниже в коде. Суть его заключается в следующем: перед каждым вызовом в «базе данных» методу в «Группе» задано поле в «База данных», общедоступное, но доступное только в частном порядке, что методы «Группы» проверяют в своих экземплярах создания ' Database 'перед выполнением намеченных операций. При чтении поля (через открытый метод в «База данных») поле сбрасывается, что предотвращает дальнейшие вызовы методов в «Группе» до тех пор, пока «База данных» снова не установит это поле.

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... 
    } 

} 

ответ

4

Один из вариантов заключается в том, чтобы разоблачить интерфейс IGroup с внешними частями вашего кода. Этот интерфейс будет иметь только атрибуты свойств, любые доступные вам методы и т. Д. Затем база данных будет работать с классом Group, имея полный доступ ко всем свойствам/методам и возвращая IGroup

+0

хорошая идея, +1 (вы должны добавить образец кода, хотя) – Jan

+0

Это выглядит для меня хорошей идеей. Кажется, он калечит автоматическую проверку типов, когда я хочу использовать «Группу» в качестве аргумента для метода «База данных» из-за пределов «Базы данных», хотя я бы вместо этого должен был передать «Группу», которая может быть реализована любым классом. Тем не менее, поскольку я могу проверять типы вручную в «базе данных» в любом случае, этот метод выглядит так, что он может существенно усложнить мой код. –

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; 

     } 
} 
0

Чтобы выразить эту видимость, используя правила доступа C#, вы должны полностью изменить класс вложенность: сделать базы данных вложенного класса внутри группы, так что он может получить доступ к частным битам группы.

+0

Я думаю, что ваш метод работает для моей проблемы, как я ее описал. Тем не менее, мне бы хотелось, чтобы этот код можно расширять, чтобы другой класс, похожий на «Группа», также был создан из «базы данных» таким же образом и с теми же ограничениями доступа. Для меня не очевидно, может ли ваш подход адаптироваться к этой проблеме. –

+0

В этом случае единственным вариантом является использование 'internal' вместо' private', поскольку CLR не имеет понятия классов друзей. Возможно, вам понадобится сделать эту объектную модель собственной сборкой, чтобы разграничить, насколько расширяется «внутренняя». –

Смежные вопросы