Как создать экземпляр объекта с помощью частного конструктора в С#?

Я определенно помню, как где-то видел пример использования рефлексии или чего-то в этом роде. Это было связано с SqlParameterCollection, который не может быть создан пользователем (если я не ошибаюсь). К сожалению уже не найти.

Может ли кто-нибудь поделиться этим трюком здесь? Не то, чтобы я считал это правильным подходом в разработке, просто меня очень интересует возможность сделать это.


person User    schedule 02.04.2009    source источник


Ответы (4)


Для этого можно использовать одну из перегрузок Activator.CreateInstance: Activator.CreateInstance(Type type, bool nonPublic)

Используйте true в качестве аргумента nonPublic. Поскольку true соответствует общедоступному или закрытому конструктору по умолчанию; а false соответствует только общедоступному конструктору по умолчанию.

Например:

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

    class Foo
    {
        private Foo()
        {
        }
    }
person Sean    schedule 02.04.2009
comment
В silverlight это соответствует CreateInstance(Type type, params object[] args);, который утомляет вызывать public ctor с аргументом bool. msdn.microsoft.com/ ru/библиотека/ - person Agent_L; 18.09.2014
comment
Это нормально, если вы вызываете конструктор без параметров. Если вы хотите вызвать частный конструктор с параметрами, попробуйте следующее: Foo f =(Foo) Activator.CreateInstance(typeof(Foo), BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { "Param1" }, null,null); - person Mohamed ElHamamsy; 08.08.2016

Если класс не принадлежит вам, то похоже, что API был специально написан, чтобы предотвратить это, а это означает, что, возможно, ваш подход не соответствует тому, что предполагали авторы API. Взгляните на документы и посмотрите, есть ли рекомендуемый подход к использованию этого класса.

Если вы делаете контроль над классом и хотите реализовать этот шаблон, то обычно он реализуется через статический метод класса. Это ключевая концепция, которая также составляет шаблон Singleton.

Например:

public PrivateCtorClass
{
    private PrivateCtorClass()
    {
    }

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

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

Материал SqlCommandParameter является хорошим примером. Они ожидают, что вы создадите параметры, вызывая такие вещи:

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

Мой пример не очень хороший код, потому что он не демонстрирует настройку свойств параметров команды или повторное использование параметров/команд, но вы поняли идею.

person Neil Barnwell    schedule 02.04.2009
comment
Я вообще-то имел в виду, если автор, если класс (не я) сделал все конструкторы приватными или внутренними и я не могу модифицировать класс, но очень-очень хочу создать его экземпляр, то как мне обойти эту защиту и создать экземпляр ? - person User; 02.04.2009
comment
Ах, я понимаю, что вы имеете в виду. Ну, похоже, что API был специально написан, чтобы предотвратить это, а это означает, что, возможно, ваш подход не соответствует тому, что планировали авторы API. Взгляните на документы и посмотрите, есть ли рекомендуемый подход к использованию этого класса. - person Neil Barnwell; 02.04.2009

Это также поможет, если ваш Type private или 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);
    }
person Mr.B    schedule 22.08.2016

person    schedule
comment
Небольшое улучшение этого удобного статического метода заключается в динамическом создании массива типов параметров. - person nrjohnstone; 09.11.2014
comment
@nrjohnstone Если вы имеете в виду GetType для каждого элемента массива, в общем случае это невозможно из-за нулей. Кроме того, если вы попытаетесь вывести типы в этом случае, вы в конечном итоге реализуете полное разрешение перегрузки в соответствии с выбранным языком, что нетривиально в случае C#. - person George Polevoy; 14.10.2015