Please Explain Behavior when Class and Member Have

2019-08-28 19:28发布

问题:

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.

回答1:

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.