Otrzymuj nowe wystąpienie obiektu z typu

głosy
554

Ktoś może nie zawsze wiedzą, typ obiektu w czasie kompilacji, ale może trzeba utworzyć instancję typu. Jak uzyskać nowe wystąpienie obiektu z typu?

Utwórz 03/08/2008 o 17:29
źródło użytkownik
W innych językach...                            


12 odpowiedzi

głosy
709

ActivatorKlasa obrębie głównego Systemobszaru nazw jest dość silny.

Istnieje wiele przeciążeń dla przekazywania parametrów do konstruktora i takie. Sprawdź dokumentację pod adresem:

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

lub (nowa droga)

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

Oto kilka prostych przykładów:

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

ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType");
Odpowiedział 03/08/2008 o 17:35
źródło użytkownik

głosy
113
ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);

ActivatorKlasa ma ogólny wariant, który sprawia, że nieco łatwiej:

ObjectType instance = Activator.CreateInstance<ObjectType>();
Odpowiedział 25/08/2008 o 14:33
źródło użytkownik

głosy
78

Kompilowane wyrażenie jest najlepszy sposób! (Dla wykonania wielokrotnie utworzyć przypadek, w czasie wykonania).

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

X x = YCreator();

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

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

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

Statystyki (2017, LINQPad 22.05.02 / 64 / .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

Pełny kod:

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) {}
}
Odpowiedział 30/04/2015 o 16:13
źródło użytkownik

głosy
35

Jedna realizacja tego problemu jest próba wywołać konstruktor parametru mniej w rodzaju:

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

Tutaj jest to samo podejście, zawarte w metodzie ogólnego:

public static T GetNewObject<T>()
{
    try
    {
        return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return default(T);
    }
}
Odpowiedział 03/08/2008 o 17:31
źródło użytkownik

głosy
11

Jeśli jest to coś, że zostanie wywołana wiele w instancji aplikacji, to dużo szybciej kompilować kod dynamiczny i cache zamiast używania lub aktywatora ConstructorInfo.Invoke(). Dwa proste opcje dynamicznej kompilacji są kompilowane Linq wyrażeń lub kilka prostych ILopcodes iDynamicMethod . Tak czy inaczej, różnica jest ogromna, gdy zaczną się w ciasnych pętli lub wielu połączeń.

Odpowiedział 25/08/2008 o 14:31
źródło użytkownik

głosy
9

Jego dość prosta. Załóżmy, że jest classname Cari przestrzeń nazw Vehicles, a następnie przekazać jako parametr Vehicles.Car, która zwraca obiekt typu Car. Jak to można utworzyć dowolną instancję każdej klasy dynamicznie.

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

Jeśli Nazwa Fully Qualified (czyli Vehicles.Carw tym przypadku) jest w innym zgromadzeń, Type.GetTypebędzie null. W takich przypadkach trzeba pętli wszystkich zespołów i odnaleźć Type. W tym celu można użyć poniższy kod

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

I można dostać instancji poprzez wywołanie powyższej metody.

object objClassInstance = GetInstance("Vehicles.Car");
Odpowiedział 03/11/2014 o 06:11
źródło użytkownik

głosy
8

Bez użycia refleksji:

private T Create<T>() where T : class, new()
{
    return new T();
}
Odpowiedział 30/06/2015 o 12:51
źródło użytkownik

głosy
7

Jeśli chcesz użyć domyślnego konstruktora następnie roztwór używając System.Activatorprezentowane wcześniej to prawdopodobnie najbardziej wygodny. Jednakże, jeśli typ brakuje domyślnego konstruktora lub trzeba użyć innego niż domyślny, a następnie opcją jest użycie odbicie lub System.ComponentModel.TypeDescriptor. W przypadku odbicia, to wystarczy znać tylko nazwę typu (z jego nazw).

Przykład użyciu odbicia:

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

Przykład zastosowania 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 }
    );
Odpowiedział 22/07/2013 o 22:03
źródło użytkownik

głosy
7

Nie będzie rodzajową T t = new T();praca?

Odpowiedział 17/08/2010 o 15:30
źródło użytkownik

głosy
5

Biorąc pod uwagę ten problem aktywator będzie działać, gdy istnieje konstruktor bez parametrów. Jeśli jest to przymus rozważyć użycie

System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()
Odpowiedział 30/06/2015 o 16:35
źródło użytkownik

głosy
3

Mogę się na to pytanie, ponieważ szukałem zaimplementować prostą metodę CloneObject dla arbitralnej klasie (z domyślnego konstruktora)

Metodą generycznych można wymagać, że typ implementuje nowy ().

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

Z nierodzajową zakładać typ ma domyślnego konstruktora i złapać wyjątek, jeśli tak nie jest.

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
Odpowiedział 24/03/2015 o 18:10
źródło użytkownik

głosy
3
public AbstractType New
{
    get
    {
        return (AbstractType) Activator.CreateInstance(GetType());
    }
}
Odpowiedział 10/09/2012 o 00:08
źródło użytkownik

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