如何通过反射从父类访问子类的非公开属性?
VB.NET父类通过反射访问子类非Public属性失败的问题
我编写了两个存在继承关系的测试类,实际代码基于DLL,因此不希望向DLL使用者暴露所有属性。我希望能够从父类通过反射访问子类的属性,但目前遇到了问题:
Public Module App Public Sub Main() Dim child As New ChildClass() child.Run() End Sub End Module Public MustInherit Class ParentClass Public Sub Run() [GetType].GetProperty("ProtectedProperty").GetValue(Me).ToString() 'Error [GetType].GetProperty("ProtectedFriendProperty").GetValue(Me).ToString() 'Error [GetType].GetProperty("FriendProperty").GetValue(Me).ToString() 'Error [GetType].GetProperty("PublicProperty").GetValue(Me).ToString() 'Success End Sub End Class Public Class ChildClass Inherits ParentClass Protected Property ProtectedProperty As String = "Protected" Protected Friend Property ProtectedFriendProperty As String = "ProtectedFriend" Friend Property FriendProperty As String = "Friend" Public Property PublicProperty As String = "Public" End Class
我原以为任意Friend属性都能被父类访问,但仅Public属性不会抛出错误。请问我是否忽略了什么关键点?
核心原因:反射的默认绑定规则与访问权限检查
GetProperty的默认行为:调用[GetType].GetProperty("属性名")时,默认仅返回Public属性成员。Protected、Friend、ProtectedFriend这类非Public成员,必须显式指定绑定标志才能被检索到。- 运行时权限检查:即便通过绑定标志拿到非Public属性的
PropertyInfo,调用GetValue时仍会触发.NET的访问权限校验:- Protected属性:父类可直接访问子类的Protected成员,但反射默认不绕过权限,需指定
BindingFlags.NonPublic+BindingFlags.Instance。 - Friend属性:Friend成员的访问范围仅限同一程序集内的所有类型,但反射默认不获取该类成员,必须指定
BindingFlags.Instance+BindingFlags.NonPublic(Friend属于NonPublic范畴)。 - ProtectedFriend属性:结合Protected与Friend的访问范围,同样需要指定正确的绑定标志才能通过反射获取。
- Protected属性:父类可直接访问子类的Protected成员,但反射默认不绕过权限,需指定
修正后的代码示例
修改父类的Run方法,显式指定绑定标志并处理权限检查:
Public MustInherit Class ParentClass Public Sub Run() ' 定义绑定标志:包含实例的Public和非Public成员 Dim bindingFlags = Reflection.BindingFlags.Instance Or Reflection.BindingFlags.Public Or Reflection.BindingFlags.NonPublic ' 访问Protected属性 Dim protectedProp = [GetType].GetProperty("ProtectedProperty", bindingFlags) If protectedProp IsNot Nothing Then Console.WriteLine(protectedProp.GetValue(Me).ToString()) End If ' 访问ProtectedFriend属性 Dim protectedFriendProp = [GetType].GetProperty("ProtectedFriendProperty", bindingFlags) If protectedFriendProp IsNot Nothing Then Console.WriteLine(protectedFriendProp.GetValue(Me).ToString()) End If ' 访问Friend属性 Dim friendProp = [GetType].GetProperty("FriendProperty", bindingFlags) If friendProp IsNot Nothing Then Console.WriteLine(friendProp.GetValue(Me).ToString()) End If ' 访问Public属性 Dim publicProp = [GetType].GetProperty("PublicProperty") If publicProp IsNot Nothing Then Console.WriteLine(publicProp.GetValue(Me).ToString()) End If End Sub End Class
额外注意事项
- 若父类与子类不在同一程序集,即使是Friend属性,父类也无法通过反射访问(Friend权限仅限同一程序集)。
- 如需绕过严格权限检查,可使用
PropertyInfo.GetValue的重载或配合BindingFlags调用,但需谨慎操作,避免破坏封装性。 - 针对DLL场景,若要隐藏属性,除使用Friend/Protected修饰外,还可添加
[EditorBrowsable(EditorBrowsableState.Never)]特性,防止属性在IntelliSense中显示,但不影响反射访问。
内容的提问来源于stack exchange,提问作者Josh
相关产品推荐
相关产品推荐

