简体   繁体   中英

How to call internal method with internal delegate argument from different assembly by reflection?

I do not have a source code for a type and need to call an internal method with an internal argument.

Is there a way to do something like this: Set.InOrderTreeWalk((object o) => o != null) ?

namespace assembly_1
{
    internal delegate bool TreeWalkPredicate<T>(Set<T>.Node node);
    public class Set<T>
    {
        private Node[] nodes;
        internal bool InOrderTreeWalk(TreeWalkPredicate<T> action)
        {
            foreach (var node in nodes)
            {
                if (!action(node))
                    return false;
            }

            return true;
        }

        internal class Node
        {
            public T Item;
        }
    }
}

Before I get into it, insert standard disclaimer about how implementation details are internal for a reason and the author doesn't owe you an explanation if something changes and it breaks your reflection code.


On the surface, the fact that the argument is of an internal delegate type does make this a bit troublesome, but there's actually a convenient way to get it: get the MethodInfo for the method we want to call and then examine its parameter.

Let's assume we already have this variable with an instance assigned:

Set<MyNode> set;

...and that the MyNode type has been declared somewhere. We want Set<MyNode>.InOrderTreeWalk to call the following method for each node in the set:

private bool MyPredicate(Set<MyNode>.Node node)
{
    return true;
}

There's not much to it, just follow the comments:

// Get the method we want to call.
MethodInfo inOrderTreeWalkMethod = set.GetType().GetMethod(
    "InOrderTreeWalk", BindingFlags.NonPublic | BindingFlags.Instance);

// Get the internal delegate type from the parameter info.  The type retrieved here
// is already close-constructed so we don't have to do any generic-related manipulation.
Type treeWalkPredicateType = inOrderTreeWalkMethod.GetParameters()[0].ParameterType;

// Get the method we want to be called for each node.
MethodInfo myPredicateMethod = GetType().GetMethod(
    nameof(MyPredicate), BindingFlags.NonPublic | BindingFlags.Instance);

// Create the delegate.  This is where the magic happens.  The runtime validates
// type compatibility and throws an exception if something's wrong.
Delegate myPredicateDelegate = myPredicateMethod.CreateDelegate(treeWalkPredicateType, this);

// Call the internal method and pass our delegate.
bool result = (bool)inOrderTreeWalkMethod.Invoke(set, new object[] { myPredicateDelegate });

Assuming you've provided enough information about the component you're using, and barring any issues with trust level, that should do it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM