Instantiating a constructor with parameters in an internal class with reflection
Asked Answered
G

4

63

I have something along the lines of this:

object[] parameter = new object[1];
parameter[0] = x;
object instantiatedType =
Activator.CreateInstance(typeToInstantiate, parameter);

and

internal class xxx : ICompare<Type>
{
    private object[] x;

    # region Constructors

    internal xxx(object[] x)
    {
        this.x = x;
    }

    internal xxx()
    {
    }

    ...
}

And I get:

threw exception: System.MissingMethodException: Constructor on type 'xxxx.xxx' not found..

Any ideas?

Grandeur answered 2/11, 2010 at 11:41 Comment(1)
I originally though you intended parameter to be the thing you passed as x. However, I just realised that's probably not what you meant and, looking at the other answers, it seems I'm not alone. If this is correct, I suggest renaming parameter to parameters. Or better still, dispense with parameter altogether: Activator.CreateInstance(typeToInstantiate, new object[]{x}).Elixir
G
104

The issue is that Activator.CreateInstance(Type, object[]) does not consider non-public constructors.

Exceptions

MissingMethodException: No matching public constructor was found.

This is easily shown by changing the constructor to publicvisibility; the code then works correctly.

Here's one workaround (tested):

 BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance;
 CultureInfo culture = null; // use InvariantCulture or other if you prefer
 object instantiatedType =   
   Activator.CreateInstance(typeToInstantiate, flags, null, parameter, culture);

If you only require the parameterless constructor this will work as well:

//using the overload: public static object CreateInstance(Type type, bool nonPublic)
object instantiatedType = Activator.CreateInstance(typeToInstantiate, true)
Gymnasium answered 2/11, 2010 at 11:50 Comment(2)
I tested this and think it's worth mentioning that this method ONLY works with non-public constructors. To make it work with both public AND non-public constructors, change the BindingFlags to BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InstanceBaelbeer
Also you don't have to use object, you can use it like this: YourType instantiatedType = (YourType)Activator.CreateInstance(typeof(YourType), true)Nick
P
34

(tested successfully)

object instantiatedType =
   Activator.CreateInstance(typeToInstantiate,
   System.Reflection.BindingFlags.NonPublic |
     System.Reflection.BindingFlags.Instance,
   null, new object[] {parameter}, null);

There are two issues this addresses:

  • the new object[] {parameter} helps it handle the issue of passing an object[] as a single parameter of method that takes a params object[] argument
  • the BindingFlags helps resolve the non-public constructor

(the two nulls relate to the binder; the default binder behaviour is fine for what we want)

Posthumous answered 2/11, 2010 at 11:52 Comment(2)
It seems like ` Activator.CreateInstance` can't determine the difference between two single-parameter constructors that accept different types...Chronometry
This approach of running Activator.CreateInstance() really makes encapsulation irrelevant. Really nice one!Judson
H
6

You need to call a different overload of Activator.CreateInstance that lets you pass a nonPublic or BindingFlags parameter.

I find all these CreateInstance overloads clumsy; what I prefer to do is:

  1. Call typeToInstantiate.GetConstructor(), passing BindingFlags.NonPublic
  2. Call ConstructorInfo.Invoke, passing it the constructor parameter
Hymnody answered 2/11, 2010 at 11:51 Comment(0)
P
3

change it to

Activator.CreateInstance(typeToInstantiate,new object[] { parameter });

This is because your constructor also expects an object array and activator already splits it up into separate objects

Piddock answered 2/11, 2010 at 11:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.