Activator.CreateInstance not working for implicit

2019-09-07 03:55发布

问题:

I'm trying to use Activator.CreateInstance Method to dynamically create a new instance. But when I pass the instance of a class that is implicitly castable to the actual type (in constructor), I get the System.MissingMethodException. Here is my testing code that I'm using to verify :

    using System;

    namespace ActivatorTest1
    {
        class Program
        {
            static void Main(string[] args)
            {
                Test t = new Test(new string[] { "abc" });
                NewClass nc = new NewClass(new SubTest("apple"));
                NewClass2 nc2 = nc;
                try
                {
                    Object[] paramList = new object[] { nc }; // nc is an instance of NewClass, which is implicitly castable to NewClass2
                    Activator.CreateInstance(typeof(Test), paramList);
                    Console.WriteLine("Instance successfully created");
                    Console.WriteLine("**************************");
                }
                catch (Exception exc)
                {
                    Console.WriteLine("INSTANCE CREATION FAILED FOR IMPLICIT CASTING SCENARIO. \r\n\r\n " + exc);
                }

                Console.WriteLine("\r\n\r\n\r\n****************************************************\r\n\r\n\r\n");
                try
                {
                    Object[] paramList = new object[] { t }; // Although t is an instance of Test which is the base class for SubTest, MissingConstructorException is thrown
                    Activator.CreateInstance(typeof(NewClass), paramList);
                    Console.WriteLine("Instance successfully created");
                    Console.WriteLine("**************************");
                }
                catch (Exception exc)
                {
                    Console.WriteLine("INSTANCE CREATION FAILED FOR DERIVED CLASS SCENARIO. \r\n " + exc);
                }
                Console.ReadKey();
            }
        }

        class Test
        {
            public Test(string[] strArr)
            { }

            public Test(NewClass2 nc2)
            { }
        }

        class SubTest : Test
        {
            public SubTest(string str)
                : base(new string[] { str })
            { }
        }

        class NewClass // implicitly castable to NewClass2
        {
            public NewClass(SubTest st)
            { }
        }

        class NewClass2
        {
            public NewClass2()
            { }

            public static implicit operator NewClass2(NewClass nc)
            {
                return new NewClass2();
            }
        }
    }

Same thing occurs when I pass in a derived class instance(which is also in the code above). So, is this the expected behavior or I'm doing something wrong in my code. What would be the proper way out for this situation. Thanks.

EDIT: About the second part, my implementation is wrong(as mentioned in the answer below), and once the code was modified accordingly, the required instance is created using derived class as parameter successfully. BUT, about the implicit casting case, still a workaround is required. Maybe some patterns-related solution, or some tricky/hacky implementation, that would generate a new instance even for implicitly castable types?

回答1:

For the first scenario:

Activator.CreateInstance(typeof(Test), new object[] { new NewClass(...) });

This call fails because the class Test has no constructor taking one argument of type NewClass. Edit: You defined an implicit cast operator, but this is not working with the reflection approach of the Activator class as it is searching for a constructor on Test which takes an argument of type NewClass and this fails. Even if the creation via the new operator works (as the cast will be evaluated prior to the new operation). For the reflection, the compiler/clr does not know it needs to perform the cast because it only looks at the types.

Maybe you intended to call the ctor with NewClass2:

Activator.CreateInstance(typeof(Test), new object[] { new NewClass2(...) });

The second call fails because you need to pass an instance of SubTest and not Test. The other way would be okay (if the ctor needs Test and you pass SubTest).

Activator.CreateInstance(typeof(NewClass), new object[] { new SubTest(...) });

The MissingMethodException is right at this point because you are trying to call a constructor which isn't defined.