如何从Type创建一个新的对象实例

在编译时可能并不总是知道对象的Type,但可能需要创建Type的实例。

如何从Type获取新对象实例?

683038 次浏览

System命名空间中的Activator类非常强大。

将参数传递给构造函数等有很多重载。查看留档:

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

或(新路径)

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

以下是一些简单的例子:

ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);
ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType");

如果这是为了在应用程序实例中经常调用的东西,那么编译和缓存动态代码而不是使用激活器或ConstructorInfo.Invoke()要快得多。动态编译的两个简单选项是编译linq表达式或一些简单的#1操作码和#2。无论哪种方式,当你开始进入紧密循环或多次调用时,差异都是巨大的。

答案已经给出了:

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

但是,Activator类有一个无参数构造函数的通用变体,通过使转换变得不必要并且不需要传递对象的运行时类型,使其更具可读性:

ObjectType instance = Activator.CreateInstance<ObjectType>();

通用T t = new T();不起作用吗?

public AbstractType New{get{return (AbstractType) Activator.CreateInstance(GetType());}}

如果您想使用默认构造函数,那么使用前面介绍的System.Activator解决方案可能是最方便的。然而,如果类型缺少默认构造函数或者您必须使用非默认构造函数,那么可以选择使用反射或System.ComponentModel.TypeDescriptor。在反射的情况下,只知道类型名称(及其命名空间)就足够了。

使用反射的示例:

ObjectType instance =(ObjectType)System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(typeName: objectType.FulName, // string including namespace of the typeignoreCase: false,bindingAttr: BindingFlags.Default,binder: null,  // use default binderargs: new object[] { args, to, constructor },culture: null, // use CultureInfo from current threadactivationAttributes: null);

使用TypeDescriptor的示例:

ObjectType instance =(ObjectType)System.ComponentModel.TypeDescriptor.CreateInstance(provider: null, // use standard type description provider, which uses reflectionobjectType: objectType,argTypes: new Type[] { types, of, args },args: new object[] { args, to, constructor });

非常简单。假设您的类名为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");

我可以回答这个问题,因为我希望为任意类实现一个简单的CloneObject方法(使用默认构造函数)

使用泛型方法,您可以要求该类型实现New()。

Public Function CloneObject(Of T As New)(ByVal src As T) As TDim result As T = NothingDim cloneable = TryCast(src, ICloneable)If cloneable IsNot Nothing Thenresult = cloneable.Clone()Elseresult = New TCopySimpleProperties(src, result, Nothing, "clone")End IfReturn resultEnd Function

对于非泛型,假设该类型具有默认构造函数和捕获如果没有,则会出现异常。

Public Function CloneObject(ByVal src As Object) As ObjectDim result As Object = NothingDim cloneable As ICloneableTrycloneable = TryCast(src, ICloneable)If cloneable IsNot Nothing Thenresult = cloneable.Clone()Elseresult = Activator.CreateInstance(src.GetType())CopySimpleProperties(src, result, Nothing, "clone")End IfCatch ex As ExceptionTrace.WriteLine("!!! CloneObject(): " & ex.Message)End TryReturn resultEnd Function

编译表达式是最好的方法!(为了在运行时重复创建实例的性能)。

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

统计数据(2012年):

    Iterations: 500000000:00:00.8481762, Activator.CreateInstance(string, string)00:00:00.8416930, Activator.CreateInstance(type)00:00:06.6236752, ConstructorInfo.Invoke00:00:00.1776255, Compiled expression00:00:00.0462197, new

统计(2015,. net 4.5,x64):

    Iterations: 500000000:00:00.2659981, Activator.CreateInstance(string, string)00:00:00.2603770, Activator.CreateInstance(type)00:00:00.7478936, ConstructorInfo.Invoke00:00:00.0700757, Compiled expression00:00:00.0286710, new

统计(2015,. net 4.5,x86):

    Iterations: 500000000:00:00.3541501, Activator.CreateInstance(string, string)00:00:00.3686861, Activator.CreateInstance(type)00:00:00.9492354, ConstructorInfo.Invoke00:00:00.0719072, Compiled expression00:00:00.0229387, new

统计(2017,LINQPad 5.22.02/x64/. NET 4.6):

    Iterations: 5000000No args00:00:00.3897563, Activator.CreateInstance(string assemblyName, string typeName)00:00:00.3500748, Activator.CreateInstance(Type type)00:00:01.0100714, ConstructorInfo.Invoke00:00:00.1375767, Compiled expression00:00:00.1337920, Compiled expression (type)00:00:00.0593664, newSingle arg00:00:03.9300630, Activator.CreateInstance(Type type)00:00:01.3881770, ConstructorInfo.Invoke00:00:00.1425534, Compiled expression00:00:00.0717409, new

统计(2019,x64/. NET 4.8):

Iterations: 5000000No args00:00:00.3287835, Activator.CreateInstance(string assemblyName, string typeName)00:00:00.3122015, Activator.CreateInstance(Type type)00:00:00.8035712, ConstructorInfo.Invoke00:00:00.0692854, Compiled expression00:00:00.0662223, Compiled expression (type)00:00:00.0337862, newSingle arg00:00:03.8081959, Activator.CreateInstance(Type type)00:00:01.2507642, ConstructorInfo.Invoke00:00:00.0671756, Compiled expression00:00:00.0301489, new

统计(2019,x64/. NET Core 3.0):

Iterations: 5000000No args00:00:00.3226895, Activator.CreateInstance(string assemblyName, string typeName)00:00:00.2786803, Activator.CreateInstance(Type type)00:00:00.6183554, ConstructorInfo.Invoke00:00:00.0483217, Compiled expression00:00:00.0485119, Compiled expression (type)00:00:00.0434534, newSingle arg00:00:03.4389401, Activator.CreateInstance(Type type)00:00:01.0803609, ConstructorInfo.Invoke00:00:00.0554756, Compiled expression00:00:00.0462232, 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) {}}

不使用反射:

private T Create<T>() where T : class, new(){return new T();}

鉴于这个问题,当存在无参数ctor时,Activator将起作用。如果这是一个约束,请考虑使用

System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()