Obtenir une nouvelle instance d’object à partir d’un type

On ne peut pas toujours connaître le type d’un object à la compilation, mais il peut être nécessaire de créer une instance du type. Comment obtenez-vous une nouvelle instance d’object d’un Type?

La classe Activator dans l’espace de noms du System racine est assez puissante.

Il y a beaucoup de surcharges pour transmettre des parameters au constructeur et à d’autres. Consultez la documentation à:

http://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx

ou (nouveau chemin)

https://docs.microsoft.com/en-us/dotnet/api/system.activator.createinstance

Voici quelques exemples simples:

 ObjectType instance = (ObjectType)Activator.CreateInstance(objectType); ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType"); 
 ObjectType instance = (ObjectType)Activator.CreateInstance(objectType); 

La classe Activator a une variante générique qui facilite les choses:

 ObjectType instance = Activator.CreateInstance(); 

L’expression compilée est la meilleure façon! (pour que les performances créent à plusieurs resockets une instance à l’exécution).

 static readonly Func YCreator = Expression.Lambda>( Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes)) ).Comstack(); X x = YCreator(); 

Statistiques (2012):

  Iterations: 5000000 00:00:00.8481762, Activator.CreateInstance(ssortingng, ssortingng) 00:00:00.8416930, Activator.CreateInstance(type) 00:00:06.6236752, ConstructorInfo.Invoke 00:00:00.1776255, Comstackd expression 00:00:00.0462197, new 

Statistiques (2015, .net 4.5, x64):

  Iterations: 5000000 00:00:00.2659981, Activator.CreateInstance(ssortingng, ssortingng) 00:00:00.2603770, Activator.CreateInstance(type) 00:00:00.7478936, ConstructorInfo.Invoke 00:00:00.0700757, Comstackd expression 00:00:00.0286710, new 

Statistiques (2015, .net 4.5, x86):

  Iterations: 5000000 00:00:00.3541501, Activator.CreateInstance(ssortingng, ssortingng) 00:00:00.3686861, Activator.CreateInstance(type) 00:00:00.9492354, ConstructorInfo.Invoke 00:00:00.0719072, Comstackd expression 00:00:00.0229387, new 

Statistiques (2017, LINQPad 5.22.02 / x64 / .NET 4.6):

  Iterations: 5000000 No args 00:00:00.3897563, Activator.CreateInstance(ssortingng assemblyName, ssortingng typeName) 00:00:00.3500748, Activator.CreateInstance(Type type) 00:00:01.0100714, ConstructorInfo.Invoke 00:00:00.1375767, Comstackd expression 00:00:00.1337920, Comstackd expression (type) 00:00:00.0593664, new Single arg 00:00:03.9300630, Activator.CreateInstance(Type type) 00:00:01.3881770, ConstructorInfo.Invoke 00:00:00.1425534, Comstackd expression 00:00:00.0717409, new 

Code complet:

 static X CreateY_New() { return new Y(); } static X CreateY_New_Arg(int z) { return new Y(z); } static X CreateY_CreateInstance() { return (X)Activator.CreateInstance(typeof(Y)); } static X CreateY_CreateInstance_Ssortingng() { return (X)Activator.CreateInstance("Program", "Y").Unwrap(); } static X CreateY_CreateInstance_Arg(int z) { return (X)Activator.CreateInstance(typeof(Y), new object[] { z, }); } private static readonly System.Reflection.ConstructorInfo YConstructor = typeof(Y).GetConstructor(Type.EmptyTypes); private static readonly object[] Empty = new object[] { }; static X CreateY_Invoke() { return (X)YConstructor.Invoke(Empty); } private static readonly System.Reflection.ConstructorInfo YConstructor_Arg = typeof(Y).GetConstructor(new[] { typeof(int), }); static X CreateY_Invoke_Arg(int z) { return (X)YConstructor_Arg.Invoke(new object[] { z, }); } private static readonly Func YCreator = Expression.Lambda>( Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes)) ).Comstack(); static X CreateY_ComstackdExpression() { return YCreator(); } private static readonly Func YCreator_Type = Expression.Lambda>( Expression.New(typeof(Y)) ).Comstack(); static X CreateY_ComstackdExpression_Type() { return YCreator_Type(); } private static readonly ParameterExpression YCreator_Arg_Param = Expression.Parameter(typeof(int), "z"); private static readonly Func YCreator_Arg = Expression.Lambda>( Expression.New(typeof(Y).GetConstructor(new[] { typeof(int), }), new[] { YCreator_Arg_Param, }), YCreator_Arg_Param ).Comstack(); static X CreateY_ComstackdExpression_Arg(int z) { return YCreator_Arg(z); } static void Main(ssortingng[] args) { const int iterations = 5000000; Console.WriteLine("Iterations: {0}", iterations); Console.WriteLine("No args"); foreach (var creatorInfo in new[] { new {Name = "Activator.CreateInstance(ssortingng assemblyName, ssortingng typeName)", Creator = (Func)CreateY_CreateInstance}, new {Name = "Activator.CreateInstance(Type type)", Creator = (Func)CreateY_CreateInstance}, new {Name = "ConstructorInfo.Invoke", Creator = (Func)CreateY_Invoke}, new {Name = "Comstackd expression", Creator = (Func)CreateY_ComstackdExpression}, new {Name = "Comstackd expression (type)", Creator = (Func)CreateY_ComstackdExpression_Type}, new {Name = "new", Creator = (Func)CreateY_New}, }) { var creator = creatorInfo.Creator; var sum = 0; for (var i = 0; i < 1000; i++) sum += creator().Z; var stopwatch = new Stopwatch(); stopwatch.Start(); for (var i = 0; i < iterations; ++i) { var x = creator(); sum += xZ; } stopwatch.Stop(); Console.WriteLine("{0}, {1}", stopwatch.Elapsed, creatorInfo.Name); } Console.WriteLine("Single arg"); foreach (var creatorInfo in new[] { new {Name = "Activator.CreateInstance(Type type)", Creator = (Func)CreateY_CreateInstance_Arg}, new {Name = "ConstructorInfo.Invoke", Creator = (Func)CreateY_Invoke_Arg}, new {Name = "Comstackd expression", Creator = (Func)CreateY_ComstackdExpression_Arg}, new {Name = "new", Creator = (Func)CreateY_New_Arg}, }) { var creator = creatorInfo.Creator; var sum = 0; for (var i = 0; i < 1000; i++) sum += creator(i).Z; var stopwatch = new Stopwatch(); stopwatch.Start(); for (var i = 0; i < iterations; ++i) { var x = creator(i); sum += xZ; } stopwatch.Stop(); Console.WriteLine("{0}, {1}", stopwatch.Elapsed, creatorInfo.Name); } } public class X { public X() { } public X(int z) { this.Z = z; } public int Z; } public class Y : X { public Y() {} public Y(int z) : base(z) {} } 

Une implémentation de ce problème consiste à tenter d’appeler le constructeur sans paramètre du Type:

 public static object GetNewObject(Type t) { try { return t.GetConstructor(new Type[] { }).Invoke(new object[] { }); } catch { return null; } } 

Voici la même approche, contenue dans une méthode générique:

 public static T GetNewObject() { try { return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { }); } catch { return default(T); } } 

C’est assez simple. Supposons que votre nom de classe est Car et que l’espace de noms soit Vehicles , puis transmettez le paramètre en tant que Vehicles.Car qui renvoie l’object de type Car . Comme cela, vous pouvez créer n’importe quelle instance de n’importe quelle classe dynamicment.

 public object GetInstance(ssortingng strNamesapace) { Type t = Type.GetType(strNamesapace); return Activator.CreateInstance(t); } 

Si votre nom Type.GetType (par exemple, Vehicles.Car dans ce cas) est dans un autre assembly, le Type.GetType sera null. Dans de tels cas, vous parcourez tous les assemblages et recherchez le Type . Pour cela, vous pouvez utiliser le code ci-dessous

 public object GetInstance(ssortingng strFullyQualifiedName) { Type type = Type.GetType(strFullyQualifiedName); if (type != null) return Activator.CreateInstance(type); foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) { type = asm.GetType(strFullyQualifiedName); if (type != null) return Activator.CreateInstance(type); } return null; } 

Et vous pouvez obtenir l’instance en appelant la méthode ci-dessus.

 object objClassInstance = GetInstance("Vehicles.Car"); 

Si c’est pour quelque chose qui sera beaucoup appelé dans une instance d’application, il est beaucoup plus rapide de comstackr et de mettre en cache le code dynamic au lieu d’utiliser l’activateur ou ConstructorInfo.Invoke() . Deux options simples pour la compilation dynamic sont les expressions Linq compilées ou quelques simples opcodes IL et DynamicMethod . Dans tous les cas, la différence est énorme lorsque vous commencez à faire des boucles serrées ou des appels multiples.

Sans utilisation de la reflection:

 private T Create() where T : class, new() { return new T(); } 

Si vous souhaitez utiliser le constructeur par défaut, la solution utilisant System.Activator présentée précédemment est probablement la plus pratique. Toutefois, si le type ne comporte pas de constructeur par défaut ou si vous devez utiliser un constructeur autre que celui par défaut, une option consiste à utiliser la reflection ou System.ComponentModel.TypeDescriptor . En cas de reflection, il suffit de connaître uniquement le nom du type (avec son espace de nommage).

Exemple utilisant la reflection:

 ObjectType instance = (ObjectType)System.Reflection.Assembly.GetExecutingAssembly().CreateInstance( typeName: objectType.FulName, // ssortingng including namespace of the type ignoreCase: false, bindingAttr: BindingFlags.Default, binder: null, // use default binder args: new object[] { args, to, constructor }, culture: null, // use CultureInfo from current thread activationAtsortingbutes: null ); 

Exemple utilisant TypeDescriptor :

 ObjectType instance = (ObjectType)System.ComponentModel.TypeDescriptor.CreateInstance( provider: null, // use standard type description provider, which uses reflection objectType: objectType, argTypes: new Type[] { types, of, args }, args: new object[] { args, to, constructor } ); 

Le générique T t = new T(); ne serait-il pas T t = new T(); travail?

Compte tenu de ce problème, l’activateur fonctionnera lorsqu’il y a un moteur sans paramètre. Si c’est une contrainte, envisagez d’utiliser

 System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject() 

Je peux à travers cette question parce que je cherchais à implémenter une méthode simple CloneObject pour la classe arbitraire (avec un constructeur par défaut)

Avec la méthode générique, vous pouvez exiger que le type implémente New ().

 Public Function CloneObject(Of T As New)(ByVal src As T) As T Dim result As T = Nothing Dim cloneable = TryCast(src, ICloneable) If cloneable IsNot Nothing Then result = cloneable.Clone() Else result = New T CopySimpleProperties(src, result, Nothing, "clone") End If Return result End Function 

Avec non-generic, le type a un constructeur par défaut et intercepte une exception si ce n’est pas le cas.

 Public Function CloneObject(ByVal src As Object) As Object Dim result As Object = Nothing Dim cloneable As ICloneable Try cloneable = TryCast(src, ICloneable) If cloneable IsNot Nothing Then result = cloneable.Clone() Else result = Activator.CreateInstance(src.GetType()) CopySimpleProperties(src, result, Nothing, "clone") End If Catch ex As Exception Trace.WriteLine("!!! CloneObject(): " & ex.Message) End Try Return result End Function 
 public AbstractType New { get { return (AbstractType) Activator.CreateInstance(GetType()); } }