Классовая иерархия в C #: как это сделать правильно? (требуется ключевое слово "друг") - PullRequest
0 голосов
/ 25 сентября 2010

У меня есть класс:

public class MyClass {  
 private List<string> folderList;  
 // .... a lot of useful public methods here.....  
}  

Все хорошо. Список папок инкапсулирован, класс доступен через открытые методы. ХОРОШО. Теперь мне нужна форма «Параметры», которая позволяет пользователю выбирать папки для MyClass. Есть одна загвоздка: новый класс Setup должен иметь доступ к частному полю folderList (или я должен предоставить публичные методы для получения и установки списка папок - это по сути то же самое) В старом добром C ++ я бы использовал функцию «друг», потому что никто, кроме класса Setup, не может получить доступ к folderList. Но в C # нет функции «друга» (я новичок в мире C #).

P.S. На самом деле я только что сделал folderList общедоступным, но я чувствую, что есть лучшее решение.

Спасибо.

Ответы [ 7 ]

3 голосов
/ 25 сентября 2010

Вы можете использовать ключевое слово "internal", чтобы сделать ваш метод доступным только в вашей сборке / проекте, и если вы хотите получить доступ к внутренним методам в другом проекте или сборке, тогда вы можете использовать атрибут "InternalsVisibleTo", где вы можете получить доступ к своим внутренним компонентам.только в той сборке, для которой вы определяете этот атрибут.

Внутреннее ключевое слово MSDN

1 голос
/ 01 октября 2010

В качестве точного ответа на вопрос я бы предложил следующее - создать отдельный интерфейс IFolderList:

interface IFolderList
{
  IList<string> FolderList { get; }
  ...
}

Ну, вы можете добавить других необходимых членов в интерфейс

В классе MyClass этот интерфейс реализован явно.

В результате класс Setup может получить доступ к данным через явное приведение к интерфейсу IFolderList или работать только с этими интерфейсами.

1 голос
/ 25 сентября 2010

Я не уверен, хотел ли он этого.Он / она не поставил требование, чтобы потенциальный клиент был в текущей сборке ... Соответственно, при использовании friend в c ++ (который никогда не считался хорошим стилем) вы должны знать тип точный класса, который будет иметь право доступа к члену.Если этот класс не является частью программы, которую вы пишете, вы не можете предоставить доступ таким образом.

Если вам нужен условный доступ к какому-либо свойству или методу экземпляра класса, вам необходимо реализовать какой-то механизм предоставления прав, например:

public IList<Folder> GetFolderList(Object pClient, IEntitlementService pService) {
 if (pService.IsEntitledToAccess(this, pClient) {
  return folderList;
 } else {
  throw new AccessNotGrantedException("...");
 }
}

Я считаю, что естьвстроенные утилиты в .Net framwork для этой цели, просто зайдите и Google (или Bing) ...

1 голос
/ 25 сентября 2010

Я считаю, что ключевое слово, которое вы ищете, - internal.Он слабо эквивалентен friend.

Internal в C ++, обеспечивающем видимость на уровне сборки.

В сочетании с предложением Femaref об использовании свойства, и вы должны иметь полное решение.

0 голосов
/ 01 октября 2010

Обнародование поля folderList - наихудший случай Предоставление подробностей реализации через открытые поля или через плохо спроектированную публичную собственность (нет различий для коллекций между публичными полями и публичной собственностью с помощью getter и setter).

С открытыми полями вы не можете рекламировать поле как свойство, если хотите добавить проверку, изменить уведомление, поместить его в интерфейс или изменить тип коллекции с одного типа на другой.

Кстати, Джеффри Рихтер в аннотации к Framework Design Guideline упомянул, что "Лично я всегда делаю свои поля приватными. Я даже не выставляю поля как внутренние , потому что это даст мне нет защиты от кода в моей собственной сборке "

Я думаю, что лучший способ добавить явный интерфейс, который предоставляет строгую абстракцию клиентам MyClass.

Например, вы можете добавить два отдельных метода для извлечения папок и добавления новой папки в это хранилище:

class MyClass {
  //You should return IList<string>
  public IList<string> MyList {get {return myList;} }

  //Or even IEnumerable<string>, because you should return
  //as minimal interface as your clients needs
  public IEnumerable<string> MyList {get {return myList;} }

  //You may expose this functionality through internal
  //method, or through protected internal method,
  //but you should avoid direct access to your implementation
  //even for descendants or another classes in your assembly
  public void AddElement(string s) {myList.Add(s);}

  private List<string> myList;
}
0 голосов
/ 25 сентября 2010

Альтернативой созданию метода internal для использования вашим классом Setup будет использование шаблона Visitor и добавление метода, который принимает экземпляр класса Setup в качестве параметра, а затем использует приватный folderList дляинициализировать / изменить Setup состояние по мере необходимости.Конечно, для этого потребуются соответствующие публичные методы класса Setup, поэтому они могут не соответствовать вашим потребностям.

0 голосов
/ 25 сентября 2010

Вот для чего нужны свойства в C #:

public class MyClass 
{
  private List folderList;

  public List FolderList
  {
    get {return folderList;}
    set {folderList = value;}
  }
}

Свойства инкапсулируют приватные поля, предоставляют возможности для проверки при настройке. Кроме того, вы должны прочитать об Generics (abit как шаблоны в c ++) и использовать List<T> вместо List, чтобы иметь строго типизированную коллекцию.

Однако вы, вероятно, не сможете достичь того, что планируете, если Setup не получен из MyClass. В этом случае вы можете использовать поле protected.

...