How to create a new object instance from a Type
可能在编译时并不总是知道对象的
根
有很多重载可以将参数传递给构造函数等等。查看文档:
http://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx
或(新路径)
https://docs.microsoft.com/en-us/dotnet/api/system.activator.createinstance
下面是一些简单的例子:
1 2 3 | ObjectType instance = (ObjectType)Activator.CreateInstance(objectType); ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType"); |
1 | ObjectType instance = (ObjectType)Activator.CreateInstance(objectType); |
1 | ObjectType instance = Activator.CreateInstance<ObjectType>(); |
编译表达式是最好的方法!(以便性能在运行时重复创建实例)。
1 2 3 4 5 |
统计(2012年):
1 2 3 4 5 6 | 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):
1 2 3 4 5 6 | 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):
1 2 3 4 5 6 | 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):
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 |
统计数据(2019年,X64/.NET 4.8):
1 2 3 4 5 6 7 8 9 10 11 12 13 | Iterations: 5000000 No args 00:00:00.3287835, Activator.CreateInstance(string assemblyName, string typeName) 00:00:00.3122015, Activator.CreateInstance(Type type) 00:00:00.8035712, ConstructorInfo.Invoke 00:00:00.0692854, Compiled expression 00:00:00.0662223, Compiled expression (type) 00:00:00.0337862, new Single arg 00:00:03.8081959, Activator.CreateInstance(Type type) 00:00:01.2507642, ConstructorInfo.Invoke 00:00:00.0671756, Compiled expression 00:00:00.0301489, new |
统计(2019,x64/.net core 3.0):
1 2 3 4 5 6 7 8 9 10 11 12 13 | Iterations: 5000000 No args 00:00:00.3226895, Activator.CreateInstance(string assemblyName, string typeName) 00:00:00.2786803, Activator.CreateInstance(Type type) 00:00:00.6183554, ConstructorInfo.Invoke 00:00:00.0483217, Compiled expression 00:00:00.0485119, Compiled expression (type) 00:00:00.0434534, new Single arg 00:00:03.4389401, Activator.CreateInstance(Type type) 00:00:01.0803609, ConstructorInfo.Invoke 00:00:00.0554756, Compiled expression 00:00:00.0462232, new |
完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | 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) {} } |
此问题的一个实现是尝试调用类型的无参数构造函数:
1 2 3 4 5 6 7 8 9 10 11 |
以下是包含在通用方法中的相同方法:
1 2 3 4 5 6 7 8 9 10 11 |
很简单。假设您的类名是
1 2 3 4 5 | public object GetInstance(string strNamesapace) { Type t = Type.GetType(strNamesapace); return Activator.CreateInstance(t); } |
如果您的完全限定名(在本例中为
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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; } |
您可以通过调用上述方法来获取实例。
1 | object objClassInstance = GetInstance("Vehicles.Car"); |
如果这是为了在应用程序实例中经常调用的东西,那么编译和缓存动态代码要比使用Activator或
不使用反射:
通用的
如果您想使用默认的构造函数,那么使用前面介绍的
使用反射的示例:
1 2 3 4 5 6 7 8 9 10 | 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 ); |
使用
1 2 3 4 5 6 7 |
考虑到这个问题,当存在无参数的ctor时,激活器将工作。如果这是一个约束,请考虑使用
1 | System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject() |
我可以解决这个问题,因为我正在为任意类(使用默认构造函数)实现一个简单的CloneObject方法。
使用泛型方法,可以要求类型实现new()。
1 2 3 4 5 6 7 8 9 10 11 |
对于非泛型,假定类型具有默认的构造函数和catch如果没有,那就例外了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 |
1 2 3 4 5 6 7 |