Získat nové instance objektu z Typu

hlasů
554

Jeden nemusí znát typ objektu při kompilaci, ale může být nutné vytvořit instanci typu. Jak se dostanete novou instanci objektu z typu?

Položena 03/08/2008 v 17:29
zdroj uživatelem
V jiných jazycích...                            


12 odpovědí

hlasů
709

ActivatorTřída v kořenovém Systemjmenném prostoru je dost silný.

Existuje spousta přetížení pro předávání parametrů do konstruktoru a podobně. Podívejte se na dokumentaci na adrese:

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

nebo (Nová cesta)

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

Zde je několik jednoduchých příkladů:

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

ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType");
Odpovězeno 03/08/2008 v 17:35
zdroj uživatelem

hlasů
113
ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);

ActivatorTřída má obecný variantu, která dělá to trochu jednodušší:

ObjectType instance = Activator.CreateInstance<ObjectType>();
Odpovězeno 25/08/2008 v 14:33
zdroj uživatelem

hlasů
78

Sestavují výraz je nejlepší způsob, jak! (Pro výkon opakovaně vytvořit instanci v běhu).

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

X x = YCreator();

Statistika (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

Statistiky (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

Statistiky (2015, .net 4,5 x 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

Statistiky (2017, LINQPad 5.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

Úplný kód:

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) {}
}
Odpovězeno 30/04/2015 v 16:13
zdroj uživatelem

hlasů
35

Jedna realizace tohoto problému je pokus o volání parametru-méně konstruktor Typ:

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

Zde je stejný přístup, který je obsažen v obecné metodě:

public static T GetNewObject<T>()
{
    try
    {
        return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return default(T);
    }
}
Odpovězeno 03/08/2008 v 17:31
zdroj uživatelem

hlasů
11

Pokud je to něco, co se bude nazývat hodně v instanci aplikace, je to mnohem rychlejší kompilace a mezipaměti dynamického kódu namísto použití aktivátor nebo ConstructorInfo.Invoke(). Dvě jednoduché možnosti pro dynamické kompilace je sestavena LINQ výrazy nebo několik jednoduchých ILopcodes aDynamicMethod . Ať tak či onak, rozdíl je obrovský, když začnete dostat do úzkých smyček nebo více hovorů.

Odpovězeno 25/08/2008 v 14:31
zdroj uživatelem

hlasů
9

Jeho docela jednoduché. Předpokládejme, že vaše classname je Cari jmenný prostor je Vehiclespak předat parametr as Vehicles.Car, která vrací objekt typu Car. Takhle si můžete vytvořit libovolné instance libovolné třídy dynamicky.

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

Pokud váš úplný název (tedy, Vehicles.Carv tomto případě) je v jiné sestavy se Type.GetTypebude nulový. V takových případech budete muset procházet všechny sestavy a najít Type. K tomu můžete použít následující kód

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

A můžete získat instanci voláním výše uvedené metody.

object objClassInstance = GetInstance("Vehicles.Car");
Odpovězeno 03/11/2014 v 06:11
zdroj uživatelem

hlasů
8

Bez použití reflexe:

private T Create<T>() where T : class, new()
{
    return new T();
}
Odpovězeno 30/06/2015 v 12:51
zdroj uživatelem

hlasů
7

Chcete-li použít výchozí konstruktor pak řešením použití System.Activatorpředložen dříve je pravděpodobně nejvhodnější. Nicméně, pokud je typ nemá výchozí konstruktor nebo budete muset použít jiný než výchozí jeden, pak možnost je použít odrazu nebo System.ComponentModel.TypeDescriptor. V případě odrazu, stačí znát pouze název typu (s jeho názvů).

Příklad pomocí reflexe:

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

Příklad použití 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 }
    );
Odpovězeno 22/07/2013 v 22:03
zdroj uživatelem

hlasů
7

Nebylo by obecný T t = new T();funguje?

Odpovězeno 17/08/2010 v 15:30
zdroj uživatelem

hlasů
5

Vzhledem k tomuto problému aktivátor bude fungovat, když je bez parametrů ctor. Pokud se jedná o omezení zvážit použití

System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()
Odpovězeno 30/06/2015 v 16:35
zdroj uživatelem

hlasů
3

Mohu přes tuto otázku, protože jsem hledal zavést jednoduchou metodu CloneObject pro svévolné třídy (s výchozí konstruktor)

S generickými metodu, kterou lze požadovat, aby typ implementuje nové ().

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

S non-generic předpokládat, že typ má výchozí konstruktor a zachytit výjimku, pokud tomu tak není.

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
Odpovězeno 24/03/2015 v 18:10
zdroj uživatelem

hlasů
3
public AbstractType New
{
    get
    {
        return (AbstractType) Activator.CreateInstance(GetType());
    }
}
Odpovězeno 10/09/2012 v 00:08
zdroj uživatelem

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