Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to instantiate an object with a private constructor in C#?

I definitely remember seeing somewhere an example of doing so using reflection or something. It was something that had to do with SqlParameterCollection which is not creatable by a user (if I'm not mistaken). Unfortunately cannot find it any longer.

Can anyone please share this trick here? Not that I consider it a valid approach in development, I'm just very interested in the possibility of doing this.

like image 389
User Avatar asked Apr 02 '09 09:04

User


People also ask

Can you create an object if a constructor is private?

A private constructor does not allow to create an object outside the class. If all the constant methods are there in our class we can use a private constructor.

How do I invoke a private constructor?

Class. getDeclaredConstructor() can be used to obtain the constructor object for the private constructor of the class. The parameter for this method is a Class object array that contains the formal parameter types of the constructor.

How do you create an instance of a class having a private constructor in C#?

class NLog { // Private Constructor: private NLog() { } public static double e = Math. E; //2.71828... } The declaration of the empty constructor prevents the automatic generation of a parameterless constructor. Note that if you do not use an access modifier with the constructor it will still be private by default.


4 Answers

You can use one of the overloads of Activator.CreateInstance to do this: Activator.CreateInstance(Type type, bool nonPublic)

Use true for the nonPublic argument. Because true matches a public or non-public default constructor; and false matches only a public default constructor.

For example:

    class Program
    {
        public static void Main(string[] args)
        {
            Type type=typeof(Foo);
            Foo f=(Foo)Activator.CreateInstance(type,true);
        }       
    }

    class Foo
    {
        private Foo()
        {
        }
    }
like image 106
Sean Avatar answered Oct 05 '22 19:10

Sean


// the types of the constructor parameters, in order
// use an empty Type[] array if the constructor takes no parameters
Type[] paramTypes = new Type[] { typeof(string), typeof(int) };

// the values of the constructor parameters, in order
// use an empty object[] array if the constructor takes no parameters
object[] paramValues = new object[] { "test", 42 };

TheTypeYouWantToInstantiate instance =
    Construct<TheTypeYouWantToInstantiate>(paramTypes, paramValues);

// ...

public static T Construct<T>(Type[] paramTypes, object[] paramValues)
{
    Type t = typeof(T);

    ConstructorInfo ci = t.GetConstructor(
        BindingFlags.Instance | BindingFlags.NonPublic,
        null, paramTypes, null);

    return (T)ci.Invoke(paramValues);
}
like image 28
LukeH Avatar answered Oct 05 '22 20:10

LukeH


If the class isn't one of yours, then it sounds like the API was deliberately written to prevent this, which means that it's possible your approach isn't what the API writers intended. Take a look at the docs and see if there's a recommended approach to using this class.

If you do have control over the class and want to implement this pattern, then it's typically implemented via a static method on a class. This is a key concept that makes up the Singleton pattern, too.

For example:

public PrivateCtorClass
{
    private PrivateCtorClass()
    {
    }

    public static PrivateCtorClass Create()
    {
        return new PrivateCtorClass();
    }
}

public SomeOtherClass
{
    public void SomeMethod()
    {
        var privateCtorClass = PrivateCtorClass.Create();
    }
}

The SqlCommandParameter stuff is a good example. They expect you to create parameters by calling things like this:

var command = IDbConnnection.CreateCommand(...);
command.Parameters.Add(command.CreateParameter(...));

My example isn't great code because it doesn't demonstrate setting command parameter properties or reuse of parameters/commands, but you get the idea.

like image 23
Neil Barnwell Avatar answered Oct 05 '22 19:10

Neil Barnwell


It will also help if your Type is private or internal:

 public static object CreatePrivateClassInstance(string typeName, object[] parameters)
    {
        Type type = AppDomain.CurrentDomain.GetAssemblies().
                 SelectMany(assembly => assembly.GetTypes()).FirstOrDefault(t => t.Name == typeName);
        return type.GetConstructors()[0].Invoke(parameters);
    }
like image 41
Mr.B Avatar answered Oct 05 '22 18:10

Mr.B