Obtenir une nouvelle instance d'objet d'un type

voix
554

On peut pas toujours savoir le type d'un objet à la compilation, mais peut-être besoin de créer une instance du type. Comment obtenez-vous une nouvelle instance d'objet d'un type?

Créé 03/08/2008 à 17:29
source utilisateur
Dans d'autres langues...                            


12 réponses

voix
709

La Activatorclasse dans la racine Systemespace de noms est assez puissant.

Il y a beaucoup de paramètres pour passer des surcharges au constructeur et tel. Consultez la documentation à l'adresse:

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

ou (nouvelle voie)

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");
Créé 03/08/2008 à 17:35
source utilisateur

voix
113
ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);

La Activatorclasse a une variante générique qui fait un peu plus facile:

ObjectType instance = Activator.CreateInstance<ObjectType>();
Créé 25/08/2008 à 14:33
source utilisateur

voix
78

expression est Compilé meilleure façon! (Pour des performances à plusieurs reprises pour créer par exemple dans l'exécution).

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

X x = YCreator();

Statistiques (2012):

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

Statistiques (2015, .net 4.5, x64):

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

Statistiques (2015, .net 4.5, x86):

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

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

    Iterations: 5000000
    No args
    00:00:00.3897563, Activator.CreateInstance(string assemblyName, string typeName)
    00:00:00.3500748, Activator.CreateInstance(Type type)
    00:00:01.0100714, ConstructorInfo.Invoke
    00:00:00.1375767, Compiled expression
    00:00:00.1337920, Compiled 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, Compiled 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_String()
{
    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<X> YCreator = Expression.Lambda<Func<X>>(
   Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes))
).Compile();
static X CreateY_CompiledExpression()
{
    return YCreator();
}

private static readonly Func<X> YCreator_Type = Expression.Lambda<Func<X>>(
   Expression.New(typeof(Y))
).Compile();
static X CreateY_CompiledExpression_Type()
{
    return YCreator_Type();
}

private static readonly ParameterExpression YCreator_Arg_Param = Expression.Parameter(typeof(int), "z");
private static readonly Func<int, X> YCreator_Arg = Expression.Lambda<Func<int, X>>(
   Expression.New(typeof(Y).GetConstructor(new[] { typeof(int), }), new[] { YCreator_Arg_Param, }),
   YCreator_Arg_Param
).Compile();
static X CreateY_CompiledExpression_Arg(int z)
{
    return YCreator_Arg(z);
}

static void Main(string[] args)
{
    const int iterations = 5000000;

    Console.WriteLine("Iterations: {0}", iterations);

    Console.WriteLine("No args");
    foreach (var creatorInfo in new[]
    {
        new {Name = "Activator.CreateInstance(string assemblyName, string typeName)", Creator = (Func<X>)CreateY_CreateInstance},
        new {Name = "Activator.CreateInstance(Type type)", Creator = (Func<X>)CreateY_CreateInstance},
        new {Name = "ConstructorInfo.Invoke", Creator = (Func<X>)CreateY_Invoke},
        new {Name = "Compiled expression", Creator = (Func<X>)CreateY_CompiledExpression},
        new {Name = "Compiled expression (type)", Creator = (Func<X>)CreateY_CompiledExpression_Type},
        new {Name = "new", Creator = (Func<X>)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 += x.Z;
        }
        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<int, X>)CreateY_CreateInstance_Arg},
        new {Name = "ConstructorInfo.Invoke", Creator = (Func<int, X>)CreateY_Invoke_Arg},
        new {Name = "Compiled expression", Creator = (Func<int, X>)CreateY_CompiledExpression_Arg},
        new {Name = "new", Creator = (Func<int, X>)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 += x.Z;
        }
        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) {}
}
Créé 30/04/2015 à 16:13
source utilisateur

voix
35

Une mise en œuvre de ce problème est d'essayer 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<T>()
{
    try
    {
        return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return default(T);
    }
}
Créé 03/08/2008 à 17:31
source utilisateur

voix
11

Si cela est quelque chose qui sera appelé beaucoup dans une instance d'application, il est beaucoup plus rapide pour compiler et code dynamique de cache au lieu d'utiliser l'activateur ou ConstructorInfo.Invoke(). Deux options faciles pour la compilation dynamique sont compilés expressions Linq ou quelques simples ILopcodes etDynamicMethod . De toute façon, la différence est énorme lorsque vous commencez à entrer dans des boucles serrées ou plusieurs appels.

Créé 25/08/2008 à 14:31
source utilisateur

voix
9

Son assez simple. Supposons que votre nom de classe est Caret l'espace de noms est Vehicles, puis passer le paramètre comme Vehicles.Carqui retourne l' objet de type Car. Comme cela , vous pouvez créer une instance d'une classe dynamique.

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

Si votre nom qualifié (c. -à- Vehicles.Cardans ce cas) est dans une autre assemblée, le Type.GetTypesera nulle. Dans ce cas, vous avez une boucle à travers toutes les assemblées et de trouver la Type. Pour cela , vous pouvez utiliser le code ci - dessous

public object GetInstance(string 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");
Créé 03/11/2014 à 06:11
source utilisateur

voix
8

Sans utilisation de la réflexion:

private T Create<T>() where T : class, new()
{
    return new T();
}
Créé 30/06/2015 à 12:51
source utilisateur

voix
7

Si vous souhaitez utiliser le constructeur par défaut alors la solution à l' aide System.Activatorprésenté plus tôt est probablement le plus pratique. Toutefois, si le type ne dispose pas d' un constructeur par défaut ou vous devez utiliser un non-défaut, une option est d'utiliser la réflexion ou System.ComponentModel.TypeDescriptor. Dans le cas de la réflexion, il suffit de savoir que le nom du type (avec son espace de noms).

Exemple utilisant la réflexion:

ObjectType instance = 
    (ObjectType)System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(
        typeName: objectType.FulName, // string 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
        activationAttributes: null
    );

Exemple d' utilisation 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 }
    );
Créé 22/07/2013 à 22:03
source utilisateur

voix
7

Ne serait pas le générique de T t = new T();travail?

Créé 17/08/2010 à 15:30
source utilisateur

voix
5

Compte tenu de ce problème, le Activator fonctionnera quand il y a un cteur parameterless. Si cela est une contrainte d'envisager d'utiliser

System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()
Créé 30/06/2015 à 16:35
source utilisateur

voix
3

Je peux sur cette question parce que je cherchais à mettre en œuvre une méthode simple de CloneObject pour la classe arbitraire (avec un constructeur par défaut)

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

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 le type non supposer générique a un constructeur par défaut et attraper une exception si elle ne fonctionne pas.

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
Créé 24/03/2015 à 18:10
source utilisateur

voix
3
public AbstractType New
{
    get
    {
        return (AbstractType) Activator.CreateInstance(GetType());
    }
}
Créé 10/09/2012 à 00:08
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more