Click here to Skip to main content
16,019,976 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
I'm trying to call a method of a class that was defined in a C# assembly. The calling code is C++/CLI. Problem: I keep getting a System.Reflection.TargetException with message "Object does not match target type."

The assembly has one public class, defined as follows:
C#
namespace CsWorker
{
    public class CsWorkerClass
    {
        public int VoidMethod()
        {
            return 777999;
        }
    }
}

This is a snippet of the calling code. On entry, the variable 'Object^ m_pWorker' contains a ref to an instance of CsWorkerClass and 'MethodInfo^ method' points to CsWorkerClass.VoidMethod. The intention is an equivalent to calling m_pWroker->VoidMethod(). Everything except the last 2 code lines were created to eliminate the more obvious reasons for the exception. The inline comments denote what the variables contain.
C++
auto objType = m_pWorker->GetType();
auto objClassName = objType->FullName; // CsWorker.CsWorkerClass
auto methodClass = method->DeclaringType;
auto methodName = method->Name; // VoidMethod
auto methodParams = method->GetParameters();
auto nParams = methodParams->Length; // 0
auto methodClassName = methodClass->FullName; // CsWorker.CsWorkerClass
_ASSERT(objType == methodClass); // passes
array<Object^>^ arg_dummy;
auto ret = method->Invoke(m_pWorker, arg_dummy/*arglist*/);

The Invoke call in the last line throws a System.Reflection.TargetException with message text "Object does not match target type."

What am I doing wrong here?

What I have tried:

This code fragment is boiled down from a more complex scenario where the method would take several parameters, so that I can rule out a mismatch of parameters.

Googled for a solution, but all solutions which I found say "you must supply the object as the first parameter to Invoke, not the object's type" - which I do.
Posted
Updated 12-Sep-23 8:08am
v2

Why are you passing a parameter (arg_dummy) to a method that takes no parameters?!
 
Share this answer
 
Comments
hans.sch 12-Sep-23 12:50pm    
@Phil J Pearson - arg_dummy is an empty array which corresponds to the empty parameter list. If I remove it, the compiler complains because Invoke requires 2 parameters. The second parameter to Invoke is of type 'object?[]?'. And in fact arg_dummy is null because I don't assign it a value.
Phil J Pearson 13-Sep-23 6:59am    
Sorry; I see now.
I see nothing wrong with your code. I reproduced it in C# and it works. I tried both null and an empty object array as the second parameter to Invoke and both worked. I tried changing the return type of VoidMethod and it still worked without any other changes. I think the problem must be in some code you're not showing.
I think you miss something around m_pWorker and the method also specify the nullptr or create an empty instance of the array arg_dummy
here is an example which will be useful - I made it with just C# but the reflection methods which you should follow is the same.
public class CsWorkerClass
{
    public int VoidMethod()
    {
        return 777999;
    }
}

static void Main(string[] args)
{
    {
        CsWorkerClass c = new CsWorkerClass();
        var t = typeof(CsWorkerClass);
        var m = t.GetMethod("VoidMethod");
        var res = m.Invoke(c, new object[] { });
        Console.WriteLine(res);
    }
    {
        object worker = null;
        {
            var assembly = Assembly.GetExecutingAssembly();
            foreach (var t in assembly.GetTypes())
            {
                if (t.IsClass && t.Name == "CsWorkerClass")
                {
                    worker = Activator.CreateInstance(t);
                    break;
                }
            }
        }
        if (worker != null)
        {
            CsWorkerClass c = new CsWorkerClass();
            var t = worker.GetType();
            MethodInfo mi = null;
            foreach (var m in t.GetMethods())
            {
                Console.WriteLine(m.Name);
                if (m.Name == "VoidMethod")
                {
                    mi = m;
                    break;
                }
            }
            if (mi != null)
            {
                var res = mi.Invoke(worker, null);
                Console.WriteLine(res);
            }
        }
    }
}
 
Share this answer
 
Silly me.
In my question, I said that this line causes the exception:
C++
auto ret = method->Invoke(m_pWorker, arg_dummy/*arglist*/);

Further, I said that m_pWorker was declared as Object^. This, of course, wasn't true. Actually, the declaration was msclr::auto_gcroot<Object^>, and the Invoke call should read:
C++
auto ret = method->Invoke(m_pWorker.get(), arg_dummy/*arglist*/);

Sometimes it helps to switch the mind to completely different tasks and then return to the problem :-)

Thanks to you who tried to lead me into the correct direction!
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900