2009-04-02 10 views
20

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

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

ответ

33
// 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); 
} 
+0

Небольшое улучшение этого удобного статического метода заключается в создании массива типов параметров динамически – nrjohnstone

+1

@nrjohnstone Если вы имеете в виду GetType для каждого элемента массива, это невозможно в общем случае из-за нулей. Кроме того, если вы попытаетесь вывести типы в этом случае, вы в конечном итоге выполните полное разрешение перегрузки в соответствии с выбранным языком, что не является тривиальным в случае C#. –

2

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

Если у вас есть do, у вас есть контроль над классом и вы хотите реализовать этот шаблон, то он обычно реализуется с помощью статического метода в классе. Это ключевая концепция, которая составляет шаблон 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(...)); 

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

+0

я на самом деле имел в виду, если автор, если класс (не я) сделал все конструкторы частные или внутренние, и я не могу изменить класс, но на самом деле, действительно хочу создать его экземпляр, то как я могу обойти эту защиту и создать экземпляр? – User

+0

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

47

Вы можете использовать один из перегруженных 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() 
     { 
     } 
    } 
+1

В silverlight это соответствует 'CreateInstance (Type type, params object [] args);' который шип вызывает ** public ** ctor с ** bool ** аргументом. http://msdn.microsoft.com/en-us/library/system.activator.createinstance%28v=vs.95%29.aspx –

+2

Это нормально, если вы вызываете конструктор без параметров. Если вы хотите вызвать частный конструктор с параметрами, попробуйте следующее: 'Foo f = (Foo) Activator.CreateInstance (typeof (Foo), BindingFlags.Instance | BindingFlags.NonPublic, null, new object [] {"Param1"}, null, null); ' –

0

Это также поможет, если ваш 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); 
    } 

 Смежные вопросы

  • Нет связанных вопросов^_^