【C#反射】动态创建类型实例
转载自:https://www.cnblogs.com/dytes/archive/2012/06/29/2569488.html
.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.Name = "schoolActivator";
- // 构造函数 创建实例
- ConstructorInfo Conmethod = school.GetConstructor(new[] { typeof(string)} );
- var schoolType= (School) Conmethod.Invoke(new[] { "南平小学"});
- schoolType.Name = "schoolType";
- //Assembly创建实例
- School schoolAssembly = (School)school.Assembly.CreateInstance("Education.School");
- schoolAssembly.Name = "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(school.Name);
- Console.WriteLine(ssse.Name);
属性操作
- // ==================:获取类型字段成员信息,并且给实例字段赋值或者获取实例字段的值
- //获取私有 字段 并且赋值思路:获取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(school.Name);
- Console.WriteLine(ssse.Name);
- //=====================================================================================
数组,委托和泛型类型的创建
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());
以上即是常用的几种创建对象实例的方式,实际应用中可以根据具体场景做选择。
【C#反射】动态创建类型实例的更多相关文章
- .Net 中的反射(动态创建类型实例) - Part.4
动态创建对象 在前面节中,我们先了解了反射,然后利用反射查看了类型信息,并学习了如何创建自定义特性,并利用反射来遍历它.可以说,前面三节,我们学习的都是反射是什么,在接下来的章节中,我们将学习反射可以 ...
- .Net 中的反射(动态创建类型实例)
动态创建对象 在前面节中,我们先了解了反射,然后利用反射查看了类型信息,并学习了如何创建自定义特性,并利用反射来遍历它.可以说,前面三节,我们学习的都是反射是什么,在接下来的章节中,我们将学习反射可以 ...
- C#反射动态创建实例并调用方法
在.Net 中,程序集(Assembly)中保存了元数据(MetaData)信息,因此就可以通过分析元数据来获取程序集中的内容,比如类,方法,属性等,这大大方便了在运行时去动态创建实例. MSDN解释 ...
- .Net配置文件——反射+配置文件存储类型实例
配置文件+反射确实去除了选择语句的繁琐,带来了优美的赶脚! 首先改进了一下类(接上文): ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ...
- C# 在运行时动态创建类型
C# 在运行时动态的创建类型,这里是通过动态生成C#源代码,然后通过编译器编译成程序集的方式实现动态创建类型 public static Assembly NewAssembly() { //创建编译 ...
- StructureMap.dll 中的 GetInstance 重载 + 如何利用 反射动态创建泛型类
public static T GetInstance<T>(ExplicitArguments args); // // Summary: // Creates a new instan ...
- 动态创建 Log4net 实例
动态创建log4net 实例 根据业务类型,动态的创建日志实例,将日志写到不同目录.常见的配置文件中统一配置,不能满足需求. 引用log4net nuget安装命令: Install-Package ...
- 从头认识java-13.9 隐式和显示的创建类型实例
对于上一章节擦除引起的问题与解决的方法有读者提出过于简单.这里解释一下:由于笔者本身也遇不到对应的问题.仅仅是凭空想像一些有可能的问题,基于水平有限,因此上一章节写的比較简单,欢迎广大读者踊跃提意见, ...
- OC 反射-->动态创建类
系统方法 NSLog(@"%s", __func__); //打印出类的方法名称,如: //打印结果:2018-02-22 10:52:15.394575+0800 DemoRun ...
随机推荐
- yum源 epel源 no package available 更换国内yum源
有时候安装软件会出现 no package available 解决办法:yum install epel-release 安装完会在/etc/yum.repos.d/目录下下生成两个repo文件: ...
- 源码分析axios(1)~源码分析、模拟axios的创建
■ 查看源码发现,起初axios[instance=bind(Axios.prototype.request, context);]是一个函数, 但后续[ utils.extend(instance, ...
- threejs - src - WebGLProgram是如何组建Shader的?
threejs - src - WebGLProgram是如何组建Shader的? WebGLProgram的构建 WebGLProgram构建的时候需要的参数如下: // \param render ...
- Docker 与 K8S学习笔记(二十)—— 使用Downward API向容器注入Pod信息
Kubernetes在创建Pod时,会为Pod和容器设置一些额外的信息,比如Pod名称.Pod IP.Node IP.Label.Annotation.资源限制等,我们经常会在应用程序中使用到这些数据 ...
- HTTPS加密证书流程(2)
目录 一:HTTPS加密证书流程 二:证书对比 三:自签证书 1.(lb服务器负载均衡代理) 2.(创建CA证书 创建密码) 3.生成自签证书(公钥),同时去掉私钥的密码(Enter) 四:证书内容解 ...
- 微服务架构 | 10.2 使用 Papertrail 实现日志聚合
目录 前言 1. Papertrail 基础知识 1.1 Papertrail 特点 1.2 Papertrail 是什么 2. 使用 Papertrail 进行日志聚合的示例 2.1 创建 Pape ...
- Luogu P1438无聊的数列
洛谷 P1438无聊的数列 题目链接 点这里! 题目描述 维护一个数列\(a_i\),支持两种操作: 给出一个长度等于 \(r-l+1\)的等差数列,首项为\(k\) 公差为\(d\) 并将它对应加到 ...
- 创建spring boot项目并添加多个模块时,启动报 错误: 找不到或无法加载主类
最近建个项目发现启动报,找不到或无法加载主类,想想肯定是自己配置出问题了,经过排查确实出问题了,(根pom中的bulid为移到子模块中去导致的),下面演示下正确的创建子模块的步奏 1. 创 ...
- linux sftp
转载请注明来源:https://www.cnblogs.com/hookjc/ sftp用法 1. 用sftp如何登录服务器 sftp 是一个交互式文件传输程式.它类似于 ftp, 但它进行加密传输, ...
- MyEclipse工程中Java Build Path中的JDK版本和Java Compiler Compiler compliance level的区别
感谢大佬:https://blog.csdn.net/shan9liang/article/details/17266519 问题起源: 今天再在ESB调用WebService测试,需要在jboss上 ...