GianT971
GianT971

Reputation: 4523

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.

Upvotes: 2

Views: 3614

Answers (2)

MaLio
MaLio

Reputation: 2540

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

Upvotes: 3

Nevyn
Nevyn

Reputation: 2683

onDrawItem should be an event, especially given the comment on its declaration type. I found this page on MSDN which should be able to help you out.

Dim tExForm As Type = assem.GetType("ExampleForm")
Dim exFormAsObj As Object = Activator.CreateInstance(tExForm)
Dim evClick As EventInfo = tExForm.GetEvent("Click")
Dim tDelegate As Type = evClick.EventHandlerType
Dim miHandler As MethodInfo = GetType(Example).GetMethod("LuckyHandler", BindingFlags.NonPublic Or BindingFlags.Instance)

Its that last bit that should be the most useful for you. Get the method info for the method linked to the event, which you can then use to either fire off the method, or link to it.

Update This page might also help.

Upvotes: 0

Related Questions