Come creare un'istanza di un oggetto con un costruttore privato in C #?
-
22-08-2019 - |
Domanda
Io sicuramente ricordo di aver visto da qualche parte un esempio di farlo utilizzando la riflessione o qualcosa del genere. Era qualcosa che aveva a che fare con SqlParameterCollection
che non è creabile da un utente (se non mi sbaglio). Purtroppo non riesce a trovare più.
Qualcuno può condividere questo trucco? Non che io considero un valido approccio in fase di sviluppo, sono solo molto interessati alla possibilità di fare questo.
Soluzione
// 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);
}
Altri suggerimenti
È possibile utilizzare uno dei sovraccarichi di Activator.CreateInstance per fare questo: Activator.CreateInstance(Type type, bool nonPublic)
Usa true
per l'argomento nonPublic
. Perché true
corrisponde a un costruttore predefinito pubblico o non pubblico; e false
corrisponde solo un costruttore di default pubblico.
Ad esempio:
class Program
{
public static void Main(string[] args)
{
Type type=typeof(Foo);
Foo f=(Foo)Activator.CreateInstance(type,true);
}
}
class Foo
{
private Foo()
{
}
}
E 'questa la domanda che erano dopo? Activator.CreateInstance con privata classe chiusa
Se la classe non è uno dei tuoi, allora suona come l'API è stato volutamente scritto per evitare questo, il che significa che è possibile il tuo approccio non è quello che gli scrittori API destinati. Date un'occhiata ai documenti e vedere se c'è un approccio consigliato di utilizzare questa classe.
Se do hanno il controllo sulla classe e vogliono implementare questo modello, quindi è in genere implementata tramite un metodo statico su una classe. Questo è un concetto chiave che rende il pattern Singleton, anche.
Ad esempio:
public PrivateCtorClass
{
private PrivateCtorClass()
{
}
public static PrivateCtorClass Create()
{
return new PrivateCtorClass();
}
}
public SomeOtherClass
{
public void SomeMethod()
{
var privateCtorClass = PrivateCtorClass.Create();
}
}
La roba SqlCommandParameter è un buon esempio. Si aspettano di creare parametri chiamando le cose in questo modo:
var command = IDbConnnection.CreateCommand(...);
command.Parameters.Add(command.CreateParameter(...));
Il mio esempio non è grande codice, perché non dimostra l'impostazione delle proprietà dei parametri di comando o riutilizzo dei parametri / comandi, ma si ottiene l'idea.
Sarà anche utile se il vostro Type
è private
o 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);
}