Activator.CreateInstance (Type) pour un type sans constructeur sans paramètre

En lisant le code existant au travail, je me demandais comment cela pouvait fonctionner. J’ai une classe définie dans un assemblage:

[Serializable] public class A { private readonly ssortingng _name; private A(ssortingng name) { _name = name; } } 

Et dans une autre assemblée:

 public void f(Type t) { object o = Activator.CreateInstance(t); } 

et cet appel simple f(typeof(A))

Je m’attendais à une exception concernant l’absence de constructeur sans paramètre, car si je comprends bien, si un ctor est déclaré, le compilateur n’est pas censé générer le constructeur public sans paramètre par défaut.

Ce code est exécuté sous .NET 2.0.

[EDIT] Je suis désolé mais j’ai mal lu le code réel … L’échantillon que j’ai fourni ne l’illustre pas. J’ai accepté la réponse de JonH car elle fournissait une bonne information.

Voir ceci: Création d’une instance de type sans constructeur par défaut en C # à l’aide de la reflection

En ce qui concerne C # 4.0, voici l’avenir également:

Publié par Microsoft le 1/4/2010 à 14h08
Nous avons examiné votre bogue et déterminé que le comportement que vous avez décrit est inhérent à sa conception. Nous archivons maintenant ce problème. Merci d’utiliser Visual Studio et le .Net Framework!

Il existe de nombreuses surcharges d’Activator.CreateInstance, celle qui accepte un seul paramètre de type n’appelle que le constructeur sans paramètre par défaut. Les constructeurs qui prennent un paramètre facultatif comme celui de votre exemple ne sont pas des constructeurs par défaut. Pour les invoquer, vous devez:

  1. utiliser une surcharge qui prend un tableau d’arguments
  2. Passer en Type.Missing comme argument
  3. Spécifiez OptionalParamBinding dans le BindingFlags

Voici un exemple:

 Activator.CreateInstance(typeof(MyClassName), BindingFlags.CreateInstance | BindingFlags.Public | BindingFlags.Instance | BindingFlags.OptionalParamBinding, null, new Object[] {Type.Missing}, null); 

Merci,

Weitao Su

Microsoft Corp.

Une alternative est:

 object obj = System.Runtime.Serialization.FormatterServices .GetUninitializedObject(t); 

qui crée l’object en mémoire mais n’exécute aucun constructeur. Effrayant.

Cela n’est peut-être pas faisable pour vous, mais le plus simple est de passer la liste des arguments après le type, comme ceci:

Activator.CreateInstance (t, “name”);

Vous voudrez penser à ce que f () essaie vraiment de faire. Devrait-il instancier un object de type A? Quelles autres classes va-t-il instancier?

Une possibilité consiste à avoir une instruction switch dans f () qui transmette les parameters corrects à CreateInstance () pour la classe A. Cela ne sera pas redimensionné, mais cela ne posera peut-être pas problème.

Il existe deux CreateInstance de confusion de CreateInstance : un qui prend un object de type System.Type tant que paramètre , un autre qui prend un paramètre de type T

Premier:

 object Activator.CreateInstance(type As Type) { } 

Deuxième:

 T Activator.CreateInstance() { } 

Le second est celui qui ne fonctionne pas pour une classe sans constructeur public sans paramètre.

Notez qu’il n’est presque jamais logique d’utiliser même le second; dans tous les cas où il serait utilisé, il serait préférable d’avoir une contrainte where T : new() sur votre classe et d’utiliser simplement le constructeur de T

La documentation MSDN convient:

En CreateInstance générale, CreateInstance n’est pas utilisé dans le code d’application, car le type doit être connu au moment de la compilation. Si le type est connu au moment de la compilation, la syntaxe d’instanciation normale peut être utilisée ( new opérateur en C #, New en Visual Basic, gcnew en C ++).

EDIT : J’ai peut-être parlé trop tôt; il semble que la première version ne soit pas censée fonctionner non plus.