calling method via reflection that takes an Action<T>. All of the method, the containing class and T are marked internal

I have an internal method like this

void Foo(Action<DB> act)

the class DB is in the same assembly and also marked internal. I can work out how to get a methodinfo for Foo but I cannot work out how to set up the callback act in the calling code. This is what I have so far (as an added spice I want to call another internal method from inside the callback)

    var tt = eng.GetType().Assembly;
    var dd = tt.GetType("Internal.DB");
    var kk = typeof(Action<>);
    Type[] targs =  { dd };
    var qq = kk.MakeGenericType(targs);
    MethodInfo dynMethod = eng.GetType().GetMethod("Foo", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { qq },null);
    dynMethod.Invoke(this, new object[] {
        ((Action<object>)(db=>{
       MethodInfo dynMethod2 = db.GetType().GetMethod("Wiz", BindingFlags.NonPublic | BindingFlags.Instance);
        dynMethod2.Invoke(db);
    })) }); 

my problem is here (I think)

((Action<object>)(db=>{

I really need

((Action<DB>)(db=>{

but I cannot do that (DB is internal), the one with object compiles but fails at run time saying that the object is of the wrong type.

2 answers

  • answered 2018-11-12 19:44 Neil

    I've changed very little of your example and got code which compiles and runs to completion. Is there a chance your DB.Wiz() is throwing an exception? If not we may need more info about which runtime is giving you this issue or a more complete example. Below example properly outputs "Hello, World!"

    .Net 4.6.1 Solution

    ConsoleApp project, has reference to Class Library namespace Internal. I've changed your dynMethod2.Invoke() to pass an empty object[] as your example did not compile with one parameter to Invoke. Also removed redundant parens around your lambda expression.

    private static void Main(string[] args)
    {
        Internal.Eng eng = new Internal.Eng();
    
        var tt = eng.GetType().Assembly;
        var dd = tt.GetType("Internal.DB");
        var kk = typeof(Action<>);
        Type[] targs = { dd };
    
        var qq = kk.MakeGenericType(targs);
    
        MethodInfo dynMethod = eng.GetType().GetMethod("Foo", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { qq }, null);
    
        dynMethod.Invoke(eng, new object[] {
            (Action<object>)(db=>{
                MethodInfo dynMethod2 = db.GetType().GetMethod("Wiz", BindingFlags.NonPublic | BindingFlags.Instance);
                dynMethod2.Invoke(db, new object[]{ });
            })
        });
    }
    

    Class library Internal namespace.

    using System;
    
    namespace Internal
    {
        public class Eng
        {
            internal void Foo(Action<DB> act) => act(new DB());
        }
    
        internal class DB
        {
            internal void Wiz()
            {
                Console.WriteLine("Hello, World!");
            }
        }
    }
    

  • answered 2018-11-12 19:54 Mark Feldman

    A bit hard figuring out exactly what it is you're trying to do, but if Wiz is a method of DB that accepts no parameters then I believe you're after something like this:

    dynMethod.Invoke(this, new object[] {
        ((Action<DB>)(db=> {
            MethodInfo dynMethod2 = db.GetType().GetMethod("Wiz", BindingFlags.NonPublic | BindingFlags.Instance);
            dynMethod2.Invoke(db, null);
    })) });