Få et nytt objekt eksempel fra en type

stemmer
570

Man kan ikke alltid vite hvilken type et objekt ved kompilering-tiden, men må kanskje opprette en forekomst av type. Hvordan får du et nytt objekt eksempel fra en type?

Publisert på 03/08/2008 klokken 16:29
kilden bruker
På andre språk...                            


12 svar

stemmer
728

Den Activatorklassen innenfor roten Systemnavnerom er ganske kraftig.

Det er mange av overbelastning for å sende parametere til konstruktøren og slikt. Sjekk ut dokumentasjon på:

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

eller (ny bane)

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

Her er noen enkle eksempler:

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

ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType");
Svarte 03/08/2008 kl. 16:35
kilden bruker

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

Den Activatorklassen har en generisk variant som gjør dette litt enklere:

ObjectType instance = Activator.CreateInstance<ObjectType>();
Svarte 25/08/2008 kl. 13:33
kilden bruker

stemmer
83

Samlet uttrykk er beste måten! (For ytelsen til gjentatte ganger å skape eksempel i kjøretid).

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

X x = YCreator();

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

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

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

Statistikk (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 kode:

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) {}
}
Svarte 30/04/2015 kl. 16:13
kilden bruker

stemmer
37

En gjennomføring av dette problemet er å forsøke å ringe parameter-mindre konstruktør av typen:

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

Her er den samme tilnærmingen, som finnes i en generisk metode:

public static T GetNewObject<T>()
{
    try
    {
        return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return default(T);
    }
}
Svarte 03/08/2008 kl. 16:31
kilden bruker

stemmer
12

Sin ganske enkel. Anta at klassenavn er Carog navnerom Vehicles, deretter passere parameter som Vehicles.Carsom returnerer objekt av type Car. Liker du dette kan du opprette en forekomst av en klasse dynamisk.

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

Hvis fullstendige navnet (dvs. Vehicles.Cari dette tilfellet) er i en annen montasje, Type.GetTypevil være null. I slike tilfeller må du sløyfe gjennom alle forsamlinger og finne den Type. For at du kan bruke under kode

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

Og du kan få forekomsten ved å kalle metoden ovenfor.

object objClassInstance = GetInstance("Vehicles.Car");
Svarte 03/11/2014 kl. 06:11
kilden bruker

stemmer
12

Hvis dette er for noe som vil bli kalt mye i et program eksempel, er det mye raskere å kompilere og cache dynamisk kode i stedet for å bruke aktivator eller ConstructorInfo.Invoke(). To enkle alternativer for dynamisk kompilering er utarbeidet LINQ uttrykk eller noen enkle ILopcodes ogDynamicMethod . Uansett, forskjellen er enorm når du begynner å få inn i trange sløyfer eller flere samtaler.

Svarte 25/08/2008 kl. 13:31
kilden bruker

stemmer
9

Uten bruk av Refleksjon:

private T Create<T>() where T : class, new()
{
    return new T();
}
Svarte 30/06/2015 kl. 12:51
kilden bruker

stemmer
7

Hvis du vil bruke standardkonstruktør så løsningen ved hjelp System.Activatorpresenteres tidligere er trolig den mest praktiske. Men hvis typen mangler en standardkonstruktør eller du må bruke en ikke-standard en, så et alternativ er å bruke refleksjon eller System.ComponentModel.TypeDescriptor. Ved refleksjon, er det nok å vite akkurat hvilken type navn (med sin navne).

Eksempel ved anvendelse av refleksjon:

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

Eksempel ved anvendelse av 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 }
    );
Svarte 22/07/2013 kl. 21:03
kilden bruker

stemmer
7

Ville ikke det generiske T t = new T();arbeid?

Svarte 17/08/2010 kl. 14:30
kilden bruker

stemmer
5

Gitt dette problemet Activator vil fungere når det er en parameterless ctor. Hvis dette er en begrensning vurdere å bruke

System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()
Svarte 30/06/2015 kl. 16:35
kilden bruker

stemmer
3

Jeg kan over dette spørsmålet fordi jeg var ute for å implementere en enkel CloneObject metode for vilkårlig klasse (med en standard konstruktør)

Med generisk metode kan du kreve at den type implementerer 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

Med ikke-generisk anta typen har en standardkonstruktør og fange et unntak hvis den ikke gjør det.

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
Svarte 24/03/2015 kl. 18:10
kilden bruker

stemmer
3
public AbstractType New
{
    get
    {
        return (AbstractType) Activator.CreateInstance(GetType());
    }
}
Svarte 09/09/2012 kl. 23:08
kilden bruker

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