none
Invoke dynamically a method with ref and out custom parameters RRS feed

  • Question

  • Hello...
    I want to invoke dynamically a (static)method from a (static) class that has some custom parameters(I meen enums or custom classes) from a .NET assembly. The method signature is like this : public static MyEnumType MyMethodName(out MyEnumType par).

    I've made a simple method that is using Reflection:
    internal static void InvokeMethod(string assemblyName, string className, string methodName, out object result, ref object[] arguments)  
    {  
                Assembly assembly = Assembly.LoadFrom(assemblyName);  
     
                // Walk through each type in the assembly  
                foreach (Type type in assembly.GetTypes())  
                {  
                    // Pick up a class  
                    if (type.IsClass == true && type.Name == className)  
                    {  
                        // Dynamically Invoke the Object                      
                        MethodInfo info = type.GetMethod(methodName);  
                        ParameterInfo[] pars = info.GetParameters();  
     
                        Type[] types = new Type[arguments.Length];  
                        for (int i = 0; i < types.Length; ++i)  
                            types[i] = pars[i].ParameterType;  
     
                        MethodInfo info1 = type.GetMethod(methodName, types);  
                        result = info1.Invoke(null, arguments);  
                        return;  
                    }  
                }  
     
                result = null;  
            } 

    When I want to invoke the method,  I am doing this:
    MyEnumType a;  
    object[] arguments = new object[]{ a };  
    object result;  
    InvokeMethod("MyAssembly.dll", "MyClassName", "MyMethodName", out result, ref arguments); 

    If I use common types like int or string, everything works, but if I want to use defined types, I am getting this exception - ArgumentException :
    Object of type 'MyNameSpace.Types.MyEnumType' cannot be converted to type 'MyNameSpace.Types.MyEnumType&'.

    Things are getting wierder... a week ago this code worked fine!!! Maybe I've made an update that screwd .NET out... don't know...

    I am using VS 2005 Pro on a Win XP SP3 and .NET 2.0 SP1 /.NET 3.0 SP1 / .NET 3.5 - the target Framework is .NET 2.0 SP1.

    Can someone tell me why this code worked and now it dosen't? Or... can you tell me a better solution to invoke dynamically a method that has out parameters?

    Thanks!

    Eusebiu
    Friday, June 6, 2008 9:10 AM

Answers

  • The easy solution is to simply add a reference to the assembly that contains Class1 so you can use its MyEnumType.  That's probably not what you're after, I'm guessing you are trying to treat the assembly as a plug-in.  That requires using interfaces.  A third assembly that is referenced both by your DLL and your EXE that contains the interfaces and types that both will need.  You'd put MyEnumType in that assembly.  You could also put an interface in that assembly so you don't have to use Reflection to invoke methods.
    Hans Passant.
    • Marked as answer by Bruno Yu Wednesday, June 11, 2008 5:39 AM
    Friday, June 6, 2008 1:39 PM
    Moderator
  • It's not possible.  You can't use Reflection if you don't have the type info.  That's a Good Thing in this case, it prevents you from doing something that is *very* inefficient.
    Hans Passant.
    • Marked as answer by Bruno Yu Wednesday, June 11, 2008 5:39 AM
    Friday, June 6, 2008 2:45 PM
    Moderator

All replies

  • I couldn't repro your problem.  Your InvokeMethod is brittle when there are overloads of the method you are trying to call.  You seem to have realized this and use the ParameterType property.  That can't work though, info1 will always be exactly the same as info since you are using the parameter types of the first method found.  The way you've got it setup right now, there is no good workaround for overloads.
    Hans Passant.
    Friday, June 6, 2008 11:51 AM
    Moderator
  • Thanks for the replay... First of all I want to say that there are no onverloads of  the method.

    To reproduce the problem, try this.
    1. Create a classlibrary project and in Class1.cs write this code:

    public static class Class1  
        {  
            public static MyEnumType MyMethodName(out MyEnumType a)  
            {  
                a = (MyEnumType)1;  
                uint b = (uint)a;  
                ++b;  
                return (MyEnumType)b;  
            }  
        }  
        public enum MyEnumType : uint  
        { } 
    2. Create a ConsoleApplication and in Program.cs write this code:
    class Program  
        {  
            static void Main(string[] args)  
            {  
                MyEnumType a = (MyEnumType)122;object[] arguments = new object[] { a };object result;  
                InvokeMethod("ClassLibrary1.dll", "Class1", "MyMethodName", out result, ref arguments);  
            }  
     
            internal static void InvokeMethod(string assemblyName, string className, string methodName, out object result, ref object[] arguments)  
            {  
                Assembly assembly = Assembly.LoadFrom(assemblyName);  
                  
                foreach (Type type in assembly.GetTypes())  
                {  
                    if (type.IsClass == true && type.Name == className)  
                    {  
                        MethodInfo info = type.GetMethod(methodName);  
                        result = info.Invoke(null, arguments);  
                        return;  
                    }  
                }  
                result = null;  
            }  
        }  
        public enum MyEnumType : uint  
        { } 
    3. Copy the ClassLibrary1.dll in the Debug folder of ConsoleApplication1.exe
    4. Run ConsoleApplication1.exe from VS and at result = info.Invoke(null, arguments); you'll get the ArgumentException = Object of type 'ConsoleApplication1.MyEnumType' cannot be converted to type 'ClassLibrary1.MyEnumType&'.

    Hope this helps you repro the problem!
    Thanks again!

    Eusebiu
    Friday, June 6, 2008 12:21 PM
  • That is normal and expected.  You've got two distinct enum types, one defined in the class assembly, the other defined in the .exe assembly.  Even though they have the same name and the same enumerated values, the CLR considers them distinct types that cannot be converted.  The error message you get when that happens tends to be confusing because it quotes the type name and they are the same.  You'll get a better message if you replace all "MyEnumType" strings to "MyOtherEnum" in the console app.
    Hans Passant.
    • Proposed as answer by Bruno Yu Wednesday, June 11, 2008 5:40 AM
    Friday, June 6, 2008 12:42 PM
    Moderator
  • OK... so it's normal... But is there a solution to do this?


    Eusebiu
    Friday, June 6, 2008 1:10 PM
  • The easy solution is to simply add a reference to the assembly that contains Class1 so you can use its MyEnumType.  That's probably not what you're after, I'm guessing you are trying to treat the assembly as a plug-in.  That requires using interfaces.  A third assembly that is referenced both by your DLL and your EXE that contains the interfaces and types that both will need.  You'd put MyEnumType in that assembly.  You could also put an interface in that assembly so you don't have to use Reflection to invoke methods.
    Hans Passant.
    • Marked as answer by Bruno Yu Wednesday, June 11, 2008 5:39 AM
    Friday, June 6, 2008 1:39 PM
    Moderator
  • Hello again... You are right... it's like a plug in... and I REALLY want to use Reflection :). I want that because other developer could make a DLL that has a class and the methods inside the class have the same signature my methods from my DLL class have. So I configure my application to load the new DLL(plug-in) and collect the results using the new DLL... I don't know if you understood me but I don't want a third assembly to be referenced by application nor by the new DLL.

    Thanks for your time!
    Eusebiu
    Friday, June 6, 2008 2:26 PM
  • It's not possible.  You can't use Reflection if you don't have the type info.  That's a Good Thing in this case, it prevents you from doing something that is *very* inefficient.
    Hans Passant.
    • Marked as answer by Bruno Yu Wednesday, June 11, 2008 5:39 AM
    Friday, June 6, 2008 2:45 PM
    Moderator
  • Maybe you can use Assembly.Load to load the new DLL, and then use reflection to do what you want.
    • Proposed as answer by Bruno Yu Wednesday, June 11, 2008 5:39 AM
    Saturday, June 7, 2008 2:49 AM