Search code examples
c#vb.netwinformsreflectioninternal

retrieve internal member of an internal nested class by reflection


Ok, thanks to ILSpy, I know that the MenuItem class contains an internal class named MenuItemData, which contains itself an internal member named onDrawItem.

Given a MenuItem, I want to retrieve the object corresponding to the member onDrawItem. But all I manage to do is to get the FieldInfo, not the object itself.

Here is my code:

            Dim obj As Object
            Dim fi As FieldInfo
            Dim item as System.Windows.Forms.MenuItem
            Dim mType As System.Type

            mType = item.GetType()

            mType = mType.GetMember("MenuItemData", BindingFlags.NonPublic)(0)

            fi = mType.GetField("onDrawItem", BindingFlags.Static Or BindingFlags.Instance Or BindingFlags.NonPublic)

            obj = fi.GetValue(item)

When reaching the last line, I get an error saying something like that (it's traduced):

The field 'onDrawItem' défined in type 'System.Windows.Forms.MenuItem+MenuItemData' is not a field of the target object of type 'System.Windows.Forms.MenuItem

I don't know what object to pass to the GetValue function on the last line. Any clue?

----EDIT----

My goal is to remove the base eventHandler of the menuItem, named DrawItem. See this post and the function RemoveClickEventin the accepted answer for a better understanding.


Solution

  • System.Type menuItemType = typeof(System.Windows.Forms.MenuItem);
    
    System.Type menuItemDataType = menuItemType.GetNestedType("MenuItemData",
        System.Reflection.BindingFlags.NonPublic);
    
    System.Reflection.FieldInfo fieldInfoOnDrawItem= menuItemDataType.GetField("onDrawItem", 
        System.Reflection.BindingFlags.NonPublic | 
        System.Reflection.BindingFlags.Instance |
        System.Reflection.BindingFlags.GetField ); 
    

    Addition: To get the value you need a reference to an instance of a MenuItemData. To do this you need to get the value via GetValue of the data field in the MenuItem instance and use that.

    System.Windows.Forms.MenuItem menuItem = new System.Windows.Forms.MenuItem();
    System.Reflection.FieldInfo fieldInfoData = menuItemType.GetField("data",
        System.Reflection.BindingFlags.NonPublic |
        System.Reflection.BindingFlags.Instance |
        System.Reflection.BindingFlags.GetField);
    
    object dataField = fieldInfoData.GetValue(menuItem);
    object onDrawItem = fieldInfoOnDrawItem.GetValue(dataField);