Hier krijg je een nieuw object bijvoorbeeld van een Type

stemmen
554

Men kan niet altijd weten het type van een object tijdens het compileren, maar kan nodig zijn om een ​​instantie van het type te creëren. Hoe maak je een nieuw object bijvoorbeeld van een soort te krijgen?

De vraag is gesteld op 03/08/2008 om 17:29
bron van user
In andere talen...                            


12 antwoorden

stemmen
35

Eén uitvoering van dit probleem is om te proberen de parameter-less constructeur van het type gesprek:

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

Hier is dezelfde aanpak, die in een generieke methode:

public static T GetNewObject<T>()
{
    try
    {
        return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return default(T);
    }
}
antwoordde op 03/08/2008 om 17:31
bron van user

stemmen
709

De Activatorklasse binnen de wortel Systemnaamruimte is vrij krachtig.

Er zijn een heleboel van overbelasting voor het doorgeven van parameters aan de constructeur en dergelijke. Check de documentatie:

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

of (nieuwe weg)

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

Hier zijn een paar eenvoudige voorbeelden:

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

ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType");
antwoordde op 03/08/2008 om 17:35
bron van user

stemmen
11

Als dit voor iets dat zal worden genoemd veel in een toepassing is het bijvoorbeeld een stuk sneller te compileren en cache dynamische code in plaats van de activator of ConstructorInfo.Invoke(). Twee eenvoudige opties voor dynamische compilatie worden samengesteld Linq Expressions of een aantal eenvoudige ILopcodes enDynamicMethod . Hoe dan ook, het verschil is enorm wanneer je begint steeds in strakke lussen of meerdere gesprekken.

antwoordde op 25/08/2008 om 14:31
bron van user

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

De Activatorklasse heeft een generieke variant dat dit een stuk makkelijker maakt:

ObjectType instance = Activator.CreateInstance<ObjectType>();
antwoordde op 25/08/2008 om 14:33
bron van user

stemmen
7

Zou het niet de generieke T t = new T();werk?

antwoordde op 17/08/2010 om 15:30
bron van user

stemmen
3
public AbstractType New
{
    get
    {
        return (AbstractType) Activator.CreateInstance(GetType());
    }
}
antwoordde op 10/09/2012 om 00:08
bron van user

stemmen
7

Als u de standaard constructor gebruik vervolgens de oplossing met behulp van System.Activatoreerder gepresenteerde is waarschijnlijk de meest handige. Echter, als het type mist een default constructor of je moet een niet-standaard een te gebruiken, dan is een optie is om reflectie of te gebruiken System.ComponentModel.TypeDescriptor. In het geval van reflectie, het is genoeg om te weten precies het soort naam (met zijn namespace).

Voorbeeld met reflectie:

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

Voorbeeld met 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 }
    );
antwoordde op 22/07/2013 om 22:03
bron van user

stemmen
9

Het is vrij eenvoudig. Neem aan dat je classname is Caren de namespace wordt Vehicles, vervolgens de parameter als Vehicles.Cardie object van het type retourneert Car. Net als deze kunt u een exemplaar van een klasse dynamisch.

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

Als uw volledige naam (dat wil zeggen, Vehicles.Carin dit geval) in een andere samenstelling, het Type.GetTypezal nul zijn. In dergelijke gevallen moet je lus door alle vergaderingen en vind het Type. Daarvoor kunt u de onderstaande code te gebruiken

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

En je kunt het exemplaar krijgen door te bellen naar de bovenstaande methode.

object objClassInstance = GetInstance("Vehicles.Car");
antwoordde op 03/11/2014 om 06:11
bron van user

stemmen
3

Ik kan over deze vraag, want ik was op zoek naar een eenvoudige CloneObject methode voor willekeurige klasse uit te voeren (met een standaard constructeur)

Met generieke methode kunt u eisen dat de implementeert nieuwe ().

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

Met non-generic neem aan dat de soort heeft een standaard constructeur en vangen een uitzondering als het niet doet.

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
antwoordde op 24/03/2015 om 18:10
bron van user

stemmen
78

Samengesteld uitdrukking is beste manier! (Voor de prestaties herhaaldelijk maken bijvoorbeeld in runtime).

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

X x = YCreator();

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

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

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

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

Volledige 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) {}
}
antwoordde op 30/04/2015 om 16:13
bron van user

stemmen
8

Zonder gebruik van de Reflectie:

private T Create<T>() where T : class, new()
{
    return new T();
}
antwoordde op 30/06/2015 om 12:51
bron van user

stemmen
5

Gezien dit probleem de Activator zal werken wanneer er een parameterloze ctor. Als dit een beperking overwegen gebruik te maken

System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()
antwoordde op 30/06/2015 om 16:35
bron van user

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