【C#反射】动态创建类型实例
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
【C#反射】动态创建类型实例
转载⾃:
.NET中除了构造函数外,还有多种⽅式可以创建类型的实例。
下⾯总结了⼏种常见的通过反射创建类型实例的⽅法。
假设我们需要创建有这样⼀个类型的实例:
public class Employee
{
public String Name { get; set; }
public Employee(String name)
{
Name = name;
}
public Employee ()
{
}
public void Say(String greeting)
{
Console.WriteLine(String.Format("Employee {0} say: {1} ", Name, greeting));
}
}
System.Activator
System.Activator类中提供了三组静态⽅法来创建类型的实例,每组⽅法均提供多个重载,适⽤不同的场景。
个别重载⽅法返回ObjectHandle对象,需要unwrap后才能获取对象实例。
CreateInstance
CreateInstanceFrom
CreateComInstanceFrom
以下实例代码演⽰了如何使⽤上述⽅法创建对象实例:
// 使⽤⽆参构造函数
var employee = (Employee)Activator.CreateInstance(typeof(Employee));
employee = Activator.CreateInstance<Employee>();
employee.Say("CreateInstance with default ctor");
// 使⽤有参构造函数
employee=(Employee)Activator.CreateInstance(typeof(Employee), new object[] { "David" });
employee.Say("CreateInstance with ctor with args");
string assembly ="Test, Version=1.0.4562.31232, Culture=neutral, PublicKeyToken=null";
string type="Test.Tests.Employee";
var employeeHandle = Activator.CreateInstance(
assembly,
type);
employee = (Employee)employeeHandle.Unwrap();
employee.Say("CreateInstance and unwrap.");
string assemblyPath=@"E:\StudyProj\ShartDev\Test\Test\bin\Debug\Test.exe";
employeeHandle = Activator.CreateInstanceFrom(
assemblyPath,
type);
employee = (Employee)employeeHandle.Unwrap();
employee.Say("CreateInstanceFrom and unwrap.");
System.AppDomain
与Activator类似,AppDomain提供了4组实例⽅法创建类型的实例。
除了创建对象外,还指定了对象所归属的AppDomain。
CreateInstance
CreateInstanceAndUnwrap
CreateInstanceFrom
CreateInstanceFromAndUnwrap
System.Type
使⽤Type.InvokerMember可以调⽤类型的⽅法、属性。
⾃然也可以通过调⽤类型的构造函数来创建⼀个类型的实例。
//直接调⽤⽆参构造函数
Object obj = typeof(Employee).InvokeMember(null, BindingFlags.CreateInstance, null, null, null);
Employee employee =obj as Employee;
employee.Say("InvokeMember default ctor");
// 使⽤带参数的构造函数
obj = typeof(Employee).InvokeMember(null, BindingFlags.CreateInstance, null, null, new object[] { "david" });
employee = obj as Employee;
((Employee)obj).Say("InvokeMember ctor with argument");
System.Reflection.ConstructorInfo
除了直接适⽤InvokerMember调⽤构造函数外,还可以先以反射的⽅式获取构造函数对应的MemberInfo,具体类型为ConstructorInfo,然后使⽤其Invoke⽅法。
// ⾸先获取构造函数,然后再Invoke
ConstructorInfo ctor = typeof(Employee).GetConstructor(new Type[] { typeof(string) });
var emp = (Employee)ctor.Invoke(new object[]{"david"});
emp.Say("ConstructorInfo");
本来⼀步可以完成的操作,分两边⾛完的确是⿇烦了些,但好处在于获取ConstructorInfo之后,后续多次调⽤Invoke时,避免重复绑定,可以提⾼效率,适⽤于需要重复多次使⽤同⼀个构造函数创建实例的场景。
反射的绑定过程是按照字符串⽐较的⽅式在程序集元数据中查找匹配的成员,速度较慢。
创建实例:4种⽅式创建类型实例
Type school = typeof(School);
//需要添加对Education.dll的引⽤才能正确执⾏
// Activator创建实例
School schoolActivator = (School)Activator.CreateInstance(school);
= "schoolActivator";
// 构造函数创建实例
ConstructorInfo Conmethod = school.GetConstructor(new[] { typeof(string)} );
var schoolType= (School) Conmethod.Invoke(new[] { "南平⼩学"});
= "schoolType";
//Assembly创建实例
School schoolAssembly = (School)school.Assembly.CreateInstance("Education.School");
= "schoolAssembly";
//InvokeMember 创建实例
// Name 第⼀个参数是是成员类型名字,构造函数是与类同名,所以只要填null。
//BindingFlags 筛选类型
//Binder type实例
//Object?[]?agrs 传⼊函数的参数,这个函数在对象实例上调⽤,所以要传⼊实参new Object[] { 2 }
Object[] args = new Object[] { 8 }; 如果没有参数那么就填null
Object obj =t.InvokeMember(null,BindingFlags.CreateInstance, null, null, args);
字段操作:获取类型字段成员信息,并且给实例字段赋值或者获取实例字段的值
//获取私有字段并且赋值思路:获取School类型信息然后⽣成实例类school,获取私有字段name信息,然后⽤这个信息对实例类就⾏赋值。
Type schoolTypeInfo = typeof(School);
FieldInfo field = schoolTypeInfo.GetField("name", BindingFlags.Instance | BindingFlags.NonPublic);
//发现⼀个⼩秘密,获取的FieldInfo 是⼀把万能的钥匙,可以对所有的实例成员进⾏操作。
School school = (School)Activator.CreateInstance(schoolTypeInfo);
School ssse = new School("dfsdfd");
field.SetValue(school, "sed");//传⼊实例,field事时保存类型信息
field.SetValue(ssse, "sed");
Console.WriteLine(field.GetValue(school));//获取实例字段的值,因为field保存字段信息,可以对实例字段直接进⾏操作
Console.WriteLine();
Console.WriteLine();
属性操作
// ==================:获取类型字段成员信息,并且给实例字段赋值或者获取实例字段的值
//获取私有字段并且赋值思路:获取School类型信息然后⽣成实例类school,获取私有字段name信息,然后⽤这个信息对实例类就⾏赋值。
Type schoolTypeInfo = typeof(School);
PropertyInfo field = schoolTypeInfo.GetProperty("Name", BindingFlags.Instance | BindingFlags.Public);
//发现⼀个⼩秘密,获取的FieldInfo 是⼀把万能的钥匙,可以对所有的实例成员进⾏操作。
School school = (School)Activator.CreateInstance(schoolTypeInfo);
School ssse = new School("dfsdfd");
field.SetValue(school, "sed");//传⼊实例,field事时保存类型信息
field.SetValue(ssse, "sed");
Console.WriteLine(field.GetValue(school));//获取实例字段的值,field保存字段信息。
Console.WriteLine();
Console.WriteLine();
//=====================================================================================
数组,委托和泛型类型的创建
Array
Array类型可以使⽤静态⽅法Array.CreateInstance⽅法创建。
Array类还提供了其他重载⽅法来创建多维数组。
var array = Array.CreateInstance(typeof(int),20);
Console.WriteLine(array.GetType().Name+"" +array.Length);
//赋值
arr.SetValue("hello", 0);
arr.SetValue("world", 1);
//取值
arr.GetValue(0);
//将其转换为静态数组
string[] cs_arr = (string[])arr;
委托
⽤Delegate.CreateDelegate创建委托
MethodInfo methodInfo = typeof(CreateInstanceTest).GetMethod("StaticDoSomething",BindingFlags.Public|BindingFlags.Static);
Delegate dele = Delegate.CreateDelegate(typeof(DoSomethingDelegate),methodInfo);
dele.DynamicInvoke("just say hi");
methodInfo.CreateDelegate 创建委托
Assembly assem = typeof(Program).Assembly;
Type tExForm = assem.GetType("EventTest.Evenform");
Form obExform = (Form)Activator.CreateInstance(tExForm);
EventInfo evClick = tExForm.GetEvent(nameof(obExform.Click));
Type tDelegate = evClick.EventHandlerType;
MethodInfo miHandler = typeof(Program).GetMethod("LuckyHandler", BindingFlags.NonPublic | BindingFlags.Instance);
//第⼀种⽅法把委托绑定到this对象的 miHandler⽅法上然后返回委托指针。
Delegate delage1 = Delegate.CreateDelegate(tDelegate, this, miHandler);
delage1.DynamicInvoke(new object(), new EventArgs());
//第⼆种⽅法把⽅法绑定到指定对象的委托上
Delegate delageMeth2= miHandler.CreateDelegate(tDelegate, this);
delageMeth2.DynamicInvoke(new object(), new EventArgs());
//第三种⽅法、⽤表达式树根据⽅法的签名创建DelegateType,然后 Methodinfo.CreateDelegate 委托
Delegate delageMeth3 = miHandler.CreateDelegate(Expression.GetDelegateType(
(from parameter in miHandler.GetParameters() select parameter.ParameterType)
.Concat(new[] { miHandler.ReturnType })
.ToArray()),this);
delageMeth3.DynamicInvoke(new object(), new EventArgs());
Generic
创建泛型类型的实例,⾸先要获取对应的开放类型(Open type)的引⽤,然后调⽤Type类型的MakeGenericType⽅法,传⼊⼀个包含泛型参数的数组即可获取⼀个封闭类型(Closed Type).使⽤该封闭类型,调⽤Activator接受Type参数的某个⽅法既可以构造出具体的实例。
Type open = typeof(Dictionary<,>);
Type closeType = open.MakeGenericType(typeof(String),typeof(object));
object obj = Activator.CreateInstance(closeType);
Console.WriteLine(obj.GetType());
以上即是常⽤的⼏种创建对象实例的⽅式,实际应⽤中可以根据具体场景做选择。