tag*_*s2k 695 .net c# reflection performance types
人们可能并不总是Type在编译时知道对象,但可能需要创建一个实例Type.你如何从一个新的对象实例Type?
Kar*_*uin 842
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");
Run Code Online (Sandbox Code Playgroud)
Kon*_*lph 136
ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);
Run Code Online (Sandbox Code Playgroud)
该Activator班有一个通用的变种,使这是一个更容易一些:
ObjectType instance = Activator.CreateInstance<ObjectType>();
Run Code Online (Sandbox Code Playgroud)
Ser*_*-Tm 116
编译表达式是最好的方法!(用于在运行时重复创建实例的性能).
static readonly Func<X> YCreator = Expression.Lambda<Func<X>>(
Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes))
).Compile();
X x = YCreator();
Run Code Online (Sandbox Code Playgroud)
统计(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
Run Code Online (Sandbox Code Playgroud)
统计(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
Run Code Online (Sandbox Code Playgroud)
统计(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
Run Code Online (Sandbox Code Playgroud)
统计(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
Run Code Online (Sandbox Code Playgroud)
完整代码:
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
Run Code Online (Sandbox Code Playgroud)
tag*_*s2k 47
此问题的一个实现是尝试调用Type的无参数构造函数:
public static object GetNewObject(Type t)
{
try
{
return t.GetConstructor(new Type[] { }).Invoke(new object[] { });
}
catch
{
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
这是一种通用方法中包含的相同方法:
public static T GetNewObject<T>()
{
try
{
return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });
}
catch
{
return default(T);
}
}
Run Code Online (Sandbox Code Playgroud)
Sar*_*avu 15
它非常简单.假设您的类名是Car和命名空间Vehicles,然后传递Vehicles.Car返回类型对象的参数Car.像这样,您可以动态创建任何类的任何实例.
public object GetInstance(string strNamesapace)
{
Type t = Type.GetType(strNamesapace);
return Activator.CreateInstance(t);
}
Run Code Online (Sandbox Code Playgroud)
如果您的完全限定名称(即,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;
}
Run Code Online (Sandbox Code Playgroud)
您可以通过调用上面的方法来获取实例.
object objClassInstance = GetInstance("Vehicles.Car");
Run Code Online (Sandbox Code Playgroud)
Tom*_*eld 14
如果这是在应用程序实例中被大量调用的东西,那么编译和缓存动态代码而不是使用激活器或更快的速度要快得多ConstructorInfo.Invoke().动态编译的两个简单选项是编译Linq表达式或一些简单的IL操作码和DynamicMethod.无论哪种方式,当您开始进入紧密循环或多个呼叫时,差异是巨大的.
BSh*_*arp 10
如果您想使用默认构造函数,那么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
);
Run Code Online (Sandbox Code Playgroud)
示例使用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 }
);
Run Code Online (Sandbox Code Playgroud)
小智 9
不使用反射:
private T Create<T>() where T : class, new()
{
return new T();
}
Run Code Online (Sandbox Code Playgroud)
鉴于此问题,当存在无参数的ctor时,Activator将工作.如果这是一个约束考虑使用
System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()
Run Code Online (Sandbox Code Playgroud)
public AbstractType New
{
get
{
return (AbstractType) Activator.CreateInstance(GetType());
}
}
Run Code Online (Sandbox Code Playgroud)