Obtener una nueva instancia de objeto de un Tipo

votos
554

Es posible que uno no siempre sepa el Tipo de un objeto en tiempo de compilación, pero puede necesitar crear una instancia del Tipo. ¿Cómo se obtiene una nueva instancia de objeto de un Tipo?

Publicado el 03/08/2008 a las 17:29
fuente por usuario
En otros idiomas...                            


12 respuestas

votos
709

La Activatorclase dentro del Systemespacio de nombres raíz es bastante poderosa.

Hay muchas sobrecargas para pasar parámetros al constructor y tal. Consulte la documentación en:

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

o (nueva ruta)

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

Aquí hay algunos ejemplos simples:

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

ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType");
Respondida el 03/08/2008 a las 17:35
fuente por usuario

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

La Activatorclase tiene una variante genérica que hace esto un poco más fácil:

ObjectType instance = Activator.CreateInstance<ObjectType>();
Respondida el 25/08/2008 a las 14:33
fuente por usuario

votos
78

expresión compilado es la mejor manera! (Para el rendimiento para crear repetidamente ejemplo, en tiempo de ejecución).

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

X x = YCreator();

Estadísticas (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

Estadísticas (2015, .NET 4.5, 64):

    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

Estadísticas (2015, .NET 4.5, 86):

    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

Estadísticas (2017, LINQPad 05.22.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

código completo:

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) {}
}
Respondida el 30/04/2015 a las 16:13
fuente por usuario

votos
35

Una implementación de este problema es intentar llamar al constructor sin parámetros del Tipo:

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

Aquí está el mismo enfoque, contenido en un método genérico:

public static T GetNewObject<T>()
{
    try
    {
        return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return default(T);
    }
}
Respondida el 03/08/2008 a las 17:31
fuente por usuario

votos
11

Si esto es para algo que se llamará mucho en una instancia de aplicación, es mucho más rápido compilar y almacenar en caché el código dinámico en lugar de usar el activador o ConstructorInfo.Invoke(). Dos opciones fáciles para la compilación dinámica son compiladas Linq Expressions o algunos ILcódigos de operaciónDynamicMethod simples y . De cualquier manera, la diferencia es enorme cuando comienzas a entrar en bucles estrechos o llamadas múltiples.

Respondida el 25/08/2008 a las 14:31
fuente por usuario

votos
9

Es bastante sencillo. Suponga que su nombre de clase es Cary el espacio de nombres es Vehicles, a continuación, pasar el parámetro como Vehicles.Carque devuelve el objeto del tipo Car. Como esto puede crear cualquier instancia de cualquier clase de forma dinámica.

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

Si su nombre completo de (es decir, Vehicles.Caren este caso) se encuentra en otro montaje, el Type.GetTypeserá nulo. En tales casos, usted tiene bucle a través de todos los conjuntos y encontrar el Type. Para que se puede usar el siguiente código

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;
 }

Y se puede obtener la instancia mediante una llamada al método anterior.

object objClassInstance = GetInstance("Vehicles.Car");
Respondida el 03/11/2014 a las 06:11
fuente por usuario

votos
8

Sin el uso de Reflexión:

private T Create<T>() where T : class, new()
{
    return new T();
}
Respondida el 30/06/2015 a las 12:51
fuente por usuario

votos
7

Si desea utilizar el constructor por defecto entonces la solución usando System.Activatorpresentado anteriormente es probablemente el más conveniente. Sin embargo, si el tipo carece de un constructor por defecto o tiene que usar uno no predeterminado, a continuación, una opción es utilizar la reflexión o System.ComponentModel.TypeDescriptor. En el caso de la reflexión, es suficiente conocer sólo el nombre del tipo (con su espacio de nombres).

Ejemplo utilizando la reflexión:

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
    );

Ejemplo utilizando 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 }
    );
Respondida el 22/07/2013 a las 22:03
fuente por usuario

votos
7

No sería el genérico de T t = new T();trabajo?

Respondida el 17/08/2010 a las 15:30
fuente por usuario

votos
5

Teniendo en cuenta este problema el activador funciona cuando hay un ctor sin parámetros. Si se trata de una restricción considere usar

System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()
Respondida el 30/06/2015 a las 16:35
fuente por usuario

votos
3

Puedo través de esta pregunta porque yo estaba buscando para poner en práctica un método simple para CloneObject clase arbitraria (con un constructor por defecto)

Con método genérico se puede exigir que el tipo implementa Nueva ().

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

Con no genérico asumir el tipo tiene un constructor por defecto y capturar una excepción si no lo hace.

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
Respondida el 24/03/2015 a las 18:10
fuente por usuario

votos
3
public AbstractType New
{
    get
    {
        return (AbstractType) Activator.CreateInstance(GetType());
    }
}
Respondida el 10/09/2012 a las 00:08
fuente por usuario

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