Получить новый экземпляр объекта от типа

голоса
554

Можно не всегда знать тип объекта во время компиляции, но, возможно, потребуется создать экземпляр типа. Как получить новый экземпляр объекта от типа?

Задан 03/08/2008 в 17:29
источник пользователем
На других языках...                            


12 ответов

голоса
709

ActivatorКласс в корневом Systemпространстве имен является довольно мощным.

Есть много перегрузок для передачи параметров в конструктор и тому подобный. Проверьте документацию по адресу:

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

или (новый путь)

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

Вот несколько простых примеров:

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

ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType");
Ответил 03/08/2008 в 17:35
источник пользователем

голоса
113
ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);

ActivatorКласс имеет общий вариант , который делает это немного проще:

ObjectType instance = Activator.CreateInstance<ObjectType>();
Ответил 25/08/2008 в 14:33
источник пользователем

голоса
78

Составитель выражение лучший способ! (Для выполнения повторно создать экземпляр во время выполнения).

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

X x = YCreator();

Статистика (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

Статистика (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

Статистика (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

Статистика (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

Полный код:

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) {}
}
Ответил 30/04/2015 в 16:13
источник пользователем

голоса
35

Одна из реализаций этой проблемы заключается в попытке вызвать без параметров конструктор Тип:

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

Вот тот же подход, который содержится в общем методе:

public static T GetNewObject<T>()
{
    try
    {
        return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return default(T);
    }
}
Ответил 03/08/2008 в 17:31
источник пользователем

голоса
11

Если это что - то , что будет называться много в экземпляре приложения, это намного быстрее , чтобы скомпилировать и кэш динамического кода вместо того , чтобы использовать активатор или ConstructorInfo.Invoke(). Два простых вариантов для динамической компиляции собраны Linq выражения или несколько простых ILопкодовDynamicMethod . В любом случае, разница огромная , когда вы начнете получать в плотную петлю или нескольких вызовов.

Ответил 25/08/2008 в 14:31
источник пользователем

голоса
9

Его довольно просто. Предположим , что ваш имя_класса является Carи пространство имен Vehicles, а затем передать параметр в Vehicles.Carкоторый возвращает объект типа Car. Как это вы можете создать любой экземпляр любого класса динамически.

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

Если полное имя (то есть, Vehicles.Carв данном случае) в другой сборке, то Type.GetTypeбудет нулевым. В таких случаях у вас есть цикл через все сборки и найти Type. Для этого вы можете использовать следующий код

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

И вы можете получить экземпляр, вызвав вышеупомянутый метод.

object objClassInstance = GetInstance("Vehicles.Car");
Ответил 03/11/2014 в 06:11
источник пользователем

голоса
8

Без использования Reflection:

private T Create<T>() where T : class, new()
{
    return new T();
}
Ответил 30/06/2015 в 12:51
источник пользователем

голоса
7

Если вы хотите использовать конструктор по умолчанию , то решение , используя System.Activatorпредставленные ранее, вероятно , является наиболее удобным. Однако, если тип не имеет конструктор по умолчанию , или вы должны использовать одну нестандартную, то вариант заключается в использовании отражения или System.ComponentModel.TypeDescriptor. В случае отражения, достаточно знать только имя типа (с его пространством имен).

Пример использования отражения:

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

Пример использования 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 }
    );
Ответил 22/07/2013 в 22:03
источник пользователем

голоса
7

Не будет ли родовая T t = new T();работа?

Ответил 17/08/2010 в 15:30
источник пользователем

голоса
5

Учитывая эту проблему Активатор будет работать, когда есть без параметров т е р. Если это ограничение рассмотреть возможность использования

System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()
Ответил 30/06/2015 в 16:35
источник пользователем

голоса
3

Я могу по этому вопросу, потому что я искал, чтобы реализовать простой метод CloneObject для любого класса (с конструктором по умолчанию)

С универсальным методом вы можете потребовать, чтобы тип реализует новый ().

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

С необщего предположить тип имеет конструктор по умолчанию и поймать исключение, если это не делает.

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
Ответил 24/03/2015 в 18:10
источник пользователем

голоса
3
public AbstractType New
{
    get
    {
        return (AbstractType) Activator.CreateInstance(GetType());
    }
}
Ответил 10/09/2012 в 00:08
источник пользователем

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