12 ответов:
The
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");
ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);The
Activatorкласс имеет общий вариант, который делает это немного проще:ObjectType instance = Activator.CreateInstance<ObjectType>();
скомпилированное выражение-это лучший способ! (для производительности, чтобы повторно создать экземпляр во время выполнения).
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, 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статистика (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) {} }
одна из реализаций этой проблемы является попытка вызвать конструктор без параметров типа:
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); } }
это довольно просто. Предположим, что ваше имя это
Carи пространство именVehicles, затем передайте параметр какVehicles.Carкоторый возвращает объект типаCar. Таким образом, вы можете создать любой экземпляр любого класса динамически.public object GetInstance(string strNamesapace) { Type t = Type.GetType(strNamesapace); return Activator.CreateInstance(t); }если Полное Наименование(т. е.
Vehicles.Carв данном случае) находится в другой сборке,Type.GetTypeбудет null. В таких случаях у вас есть цикл через все сборки и найти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");
Если это для чего-то, что будет называться много в экземпляре приложения, это намного быстрее для компиляции и кэширования динамического кода вместо использования активатора или
ConstructorInfo.Invoke(). Два простых варианта динамической компиляции компилируются Linq Выражения или какой-то простойILкоды операций иDynamicMethod. В любом случае, разница огромна, когда вы начинаете попадать в жесткие петли или несколько вызовов.
если вы хотите использовать конструктор по умолчанию, то решение с помощью
System.Activatorпредставленный ранее, вероятно, самый удобный. Однако, если в типе отсутствует конструктор по умолчанию или вы должны использовать нестандартный, то можно использовать reflection или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 } );
учитывая эту проблему, активатор будет работать, когда есть конструктор без параметров. Если это ограничение рассмотрите возможность использования
System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()
Я могу ответить на этот вопрос, потому что я хотел реализовать простой метод CloneObject для произвольного класса (с конструктором по умолчанию)
С помощью универсального метода вы можете потребовать, чтобы тип реализовывал 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С non-generic предположим, что тип имеет конструктор по умолчанию и catch исключение, если это не так.
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
Comments