I've encountered a problem which challenges my understanding of access modifiers in VB.Net. I have a class declared Friend. If I declare its properties Public, the application works. If I declare them Friend, the application fails.
Before this, I believed that, in a class declared Friend, it would make no functional difference whether I declared the members Public or Friend. I thought class access declarations applied their restrictions to all nested entities, so nested properties declared Public were effectively restricted as if they had been declared Friend. Obviously, I was wrong. Can anyone explain how access modifiers really work, or point me to the relevant documentation?
Here is a more detailed description of the situation: I have a Friend class called StripTask with properties called StripDate, HistorianDate, and TaskText. I have a collection of StripTasks (called _StripTasks) which is used as the data source for a Syncfusion GridDataBoundGrid. The way the binding works, I need to pass the name of a StripTask property to each of the grid columns so each column knows what data to display. It ends up looking something like this: _DataBoundGrid.GridBoundColumns(1).MappingName = "StripDate". When the mapped properties are declared Public, it works. When the mapped properties are declared Friend, the grid is populated with the correct number of rows, but every cell is empty.
As a follow-up question, is it a good idea to avoid things, such as this Syncfusion binding method, which require me to pass property names as strings? It just feels as if I'm inviting trouble.
No, the access level of a class does not trickle down to the members and methods. In VB all methods are Public
if you don't specify anything. If you mark something as Friend
you are saying that you don't want code outside of your assembly to be able to access it which sounds exactly like what you are seeing.
EDIT
What's important to understand is that access rules at the class level deal mostly with instantiation and typing. Imagine the following DLL that uses reflection to look at a given object's properties (which is almost definitely what Syncfusion does):
Option Explicit On
Option Strict On
Public Class Class1
Public Sub Process(ByVal obj As Object)
Dim T = obj.GetType()
Dim Props = T.GetProperties()
For Each P In Props
Trace.WriteLine(P.Name)
Next
End Sub
End Class
Then imagine the following WinForms app in a separate assembly with a reference to the above DLL:
Option Explicit On
Option Strict On
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim X As New ClassLibrary1.Class1()
Dim FC As New FriendClass()
Dim PC As New PrivateClass()
X.Process(FC)
X.Process(PC)
End Sub
Private Class PrivateClass
Public Property PublicProp As String
Friend Property FriendProp As String
Private Property PrivateProp As String
End Class
End Class
Friend Class FriendClass
Public Property PublicProp As String
Friend Property FriendProp As String
Private Property PrivateProp As String
End Class
You can pass both a Friend
class as well as a Private
class to another assembly, that's completely valid. However, on the other side the DLL won't be able to access the Friend
or Private
properties, only the Public
one. When this is run you'll see two lines in the Immediate window with PublicProp
which is the only property that it can see.