Holen Sie sich eine neue Objektinstanz von einem Typ

stimmen
554

Man kann nicht immer wissen, die Art eines Objekts zur Compile-Zeit, sondern müssen eine Instanz des Typs schaffen. Wie bekommt man eine neue Objektinstanz von einem Typ?

Veröffentlicht am 03/08/2008 um 17:29
quelle vom benutzer
In anderen Sprachen...                            


12 antworten

stimmen
709

Die ActivatorKlasse innerhalb des Root - SystemNamespace ist ziemlich mächtig.

Es gibt eine Menge von Überlastungen für Parameter an den Konstruktor und so übergeben. Schauen Sie sich die Dokumentation an:

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

oder (neuer Pfad)

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

Hier sind einige einfache Beispiele:

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

ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType");
Beantwortet am 03/08/2008 um 17:35
quelle vom benutzer

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

Die ActivatorKlasse hat eine generische Variante, das ist ein bisschen einfacher macht:

ObjectType instance = Activator.CreateInstance<ObjectType>();
Beantwortet am 25/08/2008 um 14:33
quelle vom benutzer

stimmen
78

Zusammengestellt Ausdruck ist am besten Weg! (Für die Leistung wiederholt Instanz in Laufzeit erstellen).

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

X x = YCreator();

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

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

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

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

Full-Code:

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) {}
}
Beantwortet am 30/04/2015 um 16:13
quelle vom benutzer

stimmen
35

Eine Implementierung dieses Problems besteht darin, zu versuchen, die Parameter losen Konstruktor des Typs zu nennen:

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

Hier ist der gleiche Ansatz, in einem allgemeinen Verfahren enthalten:

public static T GetNewObject<T>()
{
    try
    {
        return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return default(T);
    }
}
Beantwortet am 03/08/2008 um 17:31
quelle vom benutzer

stimmen
11

Wenn dies für etwas, das viel in einer Anwendungsinstanz aufgerufen wird, dann ist es viel schneller dynamischen Code zu kompilieren und Cache anstatt den Aktivator mit oder ConstructorInfo.Invoke(). Zwei einfache Möglichkeiten für die dynamische Erstellung zusammengestellt Linq - Ausdrücke oder ein paar einfachen ILOP - Codes undDynamicMethod . So oder so, ist der Unterschied riesig , wenn man immer in engen Schleifen oder mehrere Anrufe starten.

Beantwortet am 25/08/2008 um 14:31
quelle vom benutzer

stimmen
9

Es ist ziemlich einfach. Nehmen wir an , Ihr Klassenname ist Carund der Namespace ist Vehicles, dann übergeben Sie die Parameter wie Vehicles.Cardie Objekt vom Typ zurückgibt Car. So kann man jede Instanz jeder Klasse dynamisch erstellen.

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

Wenn Ihr Fully Qualified Name (dh Vehicles.Carin diesem Fall) in einer anderen Baugruppe ist, die Type.GetTypewird null sein. In solchen Fällen müssen Sie eine Schleife durch alle Baugruppen und finden die Type. Dazu können Sie den folgenden Code verwenden ,

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

Und Sie können die Instanz erhalten, indem die obige Methode aufrufen.

object objClassInstance = GetInstance("Vehicles.Car");
Beantwortet am 03/11/2014 um 06:11
quelle vom benutzer

stimmen
8

Ohne Verwendung der Reflexion:

private T Create<T>() where T : class, new()
{
    return new T();
}
Beantwortet am 30/06/2015 um 12:51
quelle vom benutzer

stimmen
7

Wenn Sie den Standard - Konstruktor verwenden möchten dann die Lösung unter Verwendung von weiter System.Activatorvorne ist wahrscheinlich die am bequemsten. Wenn jedoch die Art , die ein Standard - Konstruktor fehlt oder Sie haben einen Nicht-Standard ein verwenden, dann ist eine Option Reflexion zu verwenden oder System.ComponentModel.TypeDescriptor. Im Fall der Reflexion ist es ausreichend , nur die Typnamen (mit seinem Namespace) zu kennen.

Beispiel für die Verwendung Reflexion:

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

Beispiel für die Verwendung 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 }
    );
Beantwortet am 22/07/2013 um 22:03
quelle vom benutzer

stimmen
7

Wäre das nicht die allgemeine T t = new T();Arbeit?

Beantwortet am 17/08/2010 um 15:30
quelle vom benutzer

stimmen
5

In Anbetracht dieses Problems der Activator funktioniert, wenn es keine Parameter Ctor ist. Wenn dies eine Einschränkung ist, in Betracht ziehen

System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()
Beantwortet am 30/06/2015 um 16:35
quelle vom benutzer

stimmen
3

Ich auf dieser Frage, weil ich suchte ein einfaches CLONEOBJECT Verfahren für beliebige Klasse zu implementieren (mit einem Standard-Konstruktor)

Mit generischer Methode können Sie verlangen, dass der Typ implementiert 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

Bei nicht-generic nehmen die Art, die einen Standard-Konstruktor hat und eine Ausnahme fangen, wenn es nicht der Fall ist.

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
Beantwortet am 24/03/2015 um 18:10
quelle vom benutzer

stimmen
3
public AbstractType New
{
    get
    {
        return (AbstractType) Activator.CreateInstance(GetType());
    }
}
Beantwortet am 10/09/2012 um 00:08
quelle vom benutzer

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