开发者

Class hierarchy in C#: how to do it correctly? ('friend' keyword wanted)

开发者 https://www.devze.com 2023-01-18 01:50 出处:网络
I have a class: public class MyClass { private List<string> folderList; // .... a lot of useful public methods here.....

I have a class:

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

Everything is fine. The 开发者_开发知识库list of folders is encapsulated, the class is accessible through public methods. OK. Now I need an "options" form that allows a user to choose folders for MyClass. There is a catch: new Setup class must have access to private folderList field (or I have to provide public methods to get and set the folder list - it's essentially the same). In old good C++ I would use 'friend' feature because nobody but Setup class may access folderList. But there is no 'friend' feature in C# (I'm a newbie in the C# world).

P.S. Actually I just made folderList public, but I feel there is a better solution.

Thanks.


You can use "internal" keyword to make your method available only within your assembly/project and if you want to access your internal methods in other project or assembly then you can use "InternalsVisibleTo" attribute, where you can access your internals only in that assembly for which you define this attribute.

MSDN Internal Keyword


I believe the keyword you're looking for is internal. It is loosely equivilent to C++'s friend.

Internal provides assembly-level visibility.

Paired with Femaref's suggestion of using a Property, and you should have your full solution.


I am not sure if this is what he/she wanted. He/she did not put the requirement that the potential client will be in current assembly... Accordingly, when using friend in c++ (which was never considered a good style) you must know the exact type of the class which will be entitled to access the member. If this class is not part of the program you are writing, you cannot grant access this way.

If you want conditional access to some property or method of an instance of a class, you will need to implement some kind of entitlement mechanism, for example:

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

I believe there are built-in utilities in the .Net framwork for that purpose, just go and google (or bing)...


As an exact answer to the question I would suggest the following - create a separate interface IFolderList:

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

Well, you can add other required members to interface

In the class MyClass implement this interface explicitly.

As a result, the class Setup can gain access to data through an explicit cast to an interface IFolderList or work only with these interface.


An alternative to making an internal method to be used by your Setup class would be to use the Visitor pattern and add a method that takes a Setup class instance as a parameter, then uses the private folderList to initialize/change Setup state as required. Of course that would require the appropriate public methods on the Setup class, so might not fit your needs.


Making folderList field public is the worst case. Exposing implementation details through public fields or through poorly designed public property (there are no differences for collections between public fields and public property with getter and setter).

With public fields you can't promote a field to be a property when you want to add validation, change notification, put it into an interface or change your collection type from one type to another.

BTW, Jeffrey Richter in annotation to Framework Design Guideline mentioned that "Personally, I always make my fields private. I don't even expose fields as internal, because doing so would give me no protection from code in my own assembly"

I think the best way to add explicit interface that expose strict abstraction to MyClass clients.

For example, you may add two separate methods to retrieving folders and to adding new folder to this storage:

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


That's what properties are for in C#:

public class MyClass 
{
  private List folderList;

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

Properties encapsulate the private fields, provide possibilites for validation while setting. Also, you should read up on Generics (abit like templates in c++) and use List<T> instead of List to have a strongly typed collection.

However, you probably wont be able to achieve what you plan unless Setup derives from MyClass. In that case, you can use a protected field.

0

精彩评论

暂无评论...
验证码 换一张
取 消