C# 反射与dynamic最佳组合示例代码
发布时间 - 2026-01-11 03:08:16 点击率:次在 C# 中反射技术应用广泛,至于什么是反射.........你如果不了解的话,请看下段说明,否则请跳过下段。广告一下:喜欢我文章的朋友请关注一下我的blog,这也有助于提高本人写作的动力。

反射:当你背对一个|美女|或帅哥却不能回头仔细观察研究时(纯属虚构,如有巧合、纯属雷同),一面小镜子就能满足你的需求。在 C# 编程过程中也经常遇到类似的情况:有一个别人写的 dll 类库你想使用却没程序文档资料......此时通过 C# Runtime 提供的功能,你可以把该 dll 类库加载到你的程序中,并细细研究 dll 的每一部分内容,这就是 C# 中的反射。
个人认为反射最突出的优点或存在的合理性:在不修改程序原码的情况下,实现程序功能的动态调整(Runtime动态对象创建)
示例:
interface IRun {
void Run();
}
class Person : IRun
{
public void Run()
{
Console.WriteLine("走,去LOL啊!");
}
}
class Car : IRun
{
public void Run()
{
Console.WriteLine("呜...........");
}
}
class Program
{
static void Main(string[] args)
{
IRun e = new Person();
e.Run();
Console.ReadLine();
}
}
如果将上面的Run功能并不一定是由Person来执行,有时需要是Car有时需要Person。常见的解决方案是添加 if 等判断结构,如下:
static void Main(string[] args)
{
Console.WriteLine("请输入:Car或Person");
string type = Console.ReadLine();
IRun e = null;
if ("Car" == type)
{
e = new Car();
}else if("Person" == type)
{
e = new Person();
}
if(null != e)
e.Run();
Console.ReadLine();
}
这种结构确是解决了现在的需求,但并不健壮。随着 IRun 接口实现、相关类的继承的增加,上面的判断结构也会飞速增长。面向对象编程、设计模式均遵循的一大原则就是封装变换,所以上面的程序无法很好的应对变化。在此我们并不涉及 “设计模式的” 的知识,因此下面的示例代码只为简化上面的程序、并未刻意套用设计模式相关知识。如下:
static void Main(string[] args)
{
Console.WriteLine("请输入:Car或Person");
string type = Console.ReadLine();
string classPath = String.Format("namespace.{0}", type);
IRun e = Activator.CreateInstance(null, classPath).Unwrap() as IRun;
if(null != e)
e.Run();
Console.ReadLine();
}
经过上面的修改,程序可自行根据用户的输入,通过Activator.CreateInstance创建 IRun 的实例,程序此处不会再随 IRun 的实现者增多这种问题的影响而发生变化。上面的这种优点就是通过反射得到的,也是我所认为的“反射存在的合理性”。
Activator、Assembly 实现反射方式创建对象
C#中反射方式创建对象可以通过 Activator.CreateInstance(静态)和 Assembly.CreateInstance(非静态)来实现,其中Assembly.CreateInstance 内部调用的仍是Activator.CreateInstance。
根据要动态创建的类型对象是否处于当前程序集之中,可将反射创建对象分为:创建程序集内的类型对象与创建程序集外的类型对象。
创建程序集内的类型对象
private static void ReflectionIRun1(string className)
{
string classPath = String.Format("namespace.{0}", className);
//参数 null ,指出所要创建类型对象位于当前程序集
var handler = Activator.CreateInstance(null, classPath);
IRun e = (IRun)handler.Unwrap();
Console.WriteLine(e.Run());
}
private static void ReflectionIRun2(string className)
{
string classPath = String.Format("namespace.{0}", className);
//typeof(IRun).Assembly 获取 IRun 类型所在的程序集
object obj = typeof(IRun).Assembly.CreateInstance(null, classPath);
IRun e = (IRun)obj;
Console.WriteLine(e.Run());
}
创建程序集外的类型对象
项目中增加一个 类库 (另一个程序集),如下图:
添加一个 Boss 类,如下:
namespace Lib
{
public class Boss
{
private string name = "老大";
public string Name{
get {return name;}
}
public string Talk()
{
return "你们都被开除了......";
}
//老板不会算账,总是多付钱,所以很有自知之明的将Payfor设为private,防止外部人员调用
private int Payfor(int total)
{
return total + 10;
}
}
}
获取 一个 Boss 对象前,首先添加对 Lib 的引用,获取示例如下:
private static void ReflectionBoss1()
{
string classPath ="Lib.Boss";
//"Lib" 参数指明要加载的程序集(即要创建的对象类型在哪个程序集中定义)
var handler = Activator.CreateInstance("Lib", classPath);
Boss b = handler.Unwrap() as Boss;
Console.WriteLine(b.Talk());
}
private static void ReflectionBoss2()
{
string classPath ="Lib.Boss";
//Assembly.Load("Lib") 加载的程序集(即要创建的对象类型在哪个程序集中定义)
var assembly = Assembly.Load("Lib");
Boss b = (Boss)assembly.CreateInstance(classPath);
Console.WriteLine(b.Talk());
}
关于反射时CLR如何查找并定位要加载的程序集,请参考MSDN中关于反射相关的知识。
反射访问字段、调用方法(属性)
反射除可以帮我们动态创建对象外,还可帮我们动态访问对象的方法(属性)或字段,因 C# 版本不同具体方法会有变更或扩展,更深入内容请参考MSDN。下面仅作简单示例(标准用法)。
给老板改名,示例:
private static void ReflectionBoss1()
{
string classPath = "Lib.Boss";
//"Lib" 参数指明要加载的程序集(即要创建的对象类型在哪个程序集中定义)
var handler = Activator.CreateInstance("Lib", classPath);
Boss b = handler.Unwrap() as Boss;
//关键代码
FieldInfo f = b.GetType().GetField("name", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
f.SetValue(b, "小二");
Console.WriteLine("{0}:{1}", b.Name, b.Talk());
}
输出:
让老板付钱:
private static void ReflectionBoss1()
{
string classPath = "Lib.Boss";
//"Lib" 参数指明要加载的程序集(即要创建的对象类型在哪个程序集中定义)
var handler = Activator.CreateInstance("Lib", classPath);
Boss b = handler.Unwrap() as Boss;
//关键代码
MethodInfo method = b.GetType().GetMethod("Payfor", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance);
object money = method.Invoke(b, new object[] { 10 });
Console.WriteLine("DW039:老大给我报销10元钱车费......");
Console.WriteLine("{0}:.....,算不清了,给你这些吧。",b.Name);
Console.WriteLine("DW039:......");
Console.WriteLine("{0}:{1}", b.Name,money);
Console.WriteLine("DW039:老大你真棒!");
}
输出:
dynamic 与 反射 双剑合璧
因为反射是运行时的类型操作,所以在编程时面临类型不确定的问题。根据上一篇《C# 匿名对象(匿名类型)、var、动态类型 dynamic》讲得 dynamic 动态类型结合我们编写的反射程序,可以大大优化程序逻辑(访问受保护级别限制的代码不在此范围内)。
上面代码的优化:
private static void ReflectionBoss1()
{
string classPath ="Lib.Boss";
var handler = Activator.CreateInstance("Lib", classPath);
dynamic b = handler.Unwrap();
Console.WriteLine(b.Talk());
}
private static void ReflectionBoss2()
{
string classPath ="Lib.Boss";
var assembly = Assembly.Load("Lib");
dynamic b = assembly.CreateInstance(classPath);
Console.WriteLine(b.Talk());
}
通过 dynamic 动态类型对象 b 来调用反射得到对象的属性、方法可直接调用,从而省去了频繁的类型转换操作。
反射常见应用场景
应用场景我印象最深刻的是 MS Petshop 示例,从SQL Server 数据库切换到 oracle 数据库时反射获得不同的数据访问层。然我实际项目中从未遇到过中途切换数据库的情况,其他应用场景基本类似上面的示例。如果朋友你发现更多的应用场景,请给予补充,3ks。
反射的优缺点
优点:反射使程序更灵活
缺点:反射运行速度相对较慢
至于反射相比普通程序慢,我没有进行过测试也不打算进行。现实情况是:Ms提倡使用 dynamic、Mvc流行、Ms对CLR不断优化、机器性能的提升,所以你在开发中无需过多考虑反射的性能问题。如果你写的程序运行速度出现了瓶颈(应首先确保自己程序写的合理),研究一下数据库优化、数据缓存、web缓存、负载均衡等技术我认为更实际一些。
# c
# dynamic
# 反射
# 详解C# 匿名对象(匿名类型)、var、动态类型 dynamic
# C# dynamic关键字的使用方法
# C#动态对象(dynamic)详解(实现方法和属性的动态)
# C# Dynamic关键字之:dynamic为什么比反射快的详解
# C#使用dynamic类型访问JObject对象
# C#中dynamic关键字的正确用法(推荐)
# 深入浅析C#中的var和dynamic
# c#使用dynamic类型优化反射的方法
# c# dynamic的使用详解
# C#中dynamic动态类型的具体使用
# 加载
# 在此
# 类库
# 请输入
# 请参考
# 运行速度
# 的是
# 也不
# 给我
# 很好
# 会有
# 给你
# 也会
# 你可以
# 就能
# 这就是
# 如有
# 是由
# 你在
# 当你
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Laravel如何配置和使用队列处理异步任务_Laravel队列驱动与任务分发实例
大型企业网站制作流程,做网站需要注册公司吗?
利用 Google AI 进行 YouTube 视频 SEO 描述优化
如何确保西部建站助手FTP传输的安全性?
Laravel怎么上传文件_Laravel图片上传及存储配置
Laravel如何配置和使用缓存?(Redis代码示例)
百度浏览器如何管理插件 百度浏览器插件管理方法
网页制作模板网站推荐,网页设计海报之类的素材哪里好?
Laravel的路由模型绑定怎么用_Laravel Route Model Binding简化控制器逻辑
Laravel如何处理JSON字段_Eloquent原生JSON字段类型操作教程
google浏览器怎么清理缓存_谷歌浏览器清除缓存加速详细步骤
,怎么在广州志愿者网站注册?
如何在新浪SAE免费搭建个人博客?
jquery插件bootstrapValidator表单验证详解
Android滚轮选择时间控件使用详解
JS实现鼠标移上去显示图片或微信二维码
独立制作一个网站多少钱,建立网站需要花多少钱?
手机软键盘弹出时影响布局的解决方法
标准网站视频模板制作软件,现在有哪个网站的视频编辑素材最齐全的,背景音乐、音效等?
Laravel怎么连接多个数据库_Laravel多数据库连接配置
制作旅游网站html,怎样注册旅游网站?
制作ppt免费网站有哪些,有哪些比较好的ppt模板下载网站?
php中::能调用final静态方法吗_final修饰静态方法调用规则【解答】
家族网站制作贴纸教程视频,用豆子做粘帖画怎么制作?
Python面向对象测试方法_mock解析【教程】
Laravel如何实现本地化和多语言支持?(i18n教程)
Laravel如何保护应用免受CSRF攻击?(原理和示例)
INTERNET浏览器怎样恢复关闭标签页_INTERNET浏览器标签恢复快捷键与方法【指南】
Laravel如何实现模型的全局作用域?(Global Scope示例)
Win11搜索栏无法输入_解决Win11开始菜单搜索没反应问题【技巧】
惠州网站建设制作推广,惠州市华视达文化传媒有限公司怎么样?
Swift中循环语句中的转移语句 break 和 continue
如何用景安虚拟主机手机版绑定域名建站?
北京网站制作公司哪家好一点,北京租房网站有哪些?
javascript事件捕获机制【深入分析IE和DOM中的事件模型】
如何在建站宝盒中设置产品搜索功能?
Laravel如何使用Seeder填充数据_Laravel模型工厂Factory批量生成测试数据【方法】
b2c电商网站制作流程,b2c水平综合的电商平台?
php 三元运算符实例详细介绍
小视频制作网站有哪些,有什么看国内小视频的网站,求推荐?
香港服务器部署网站为何提示未备案?
iOS正则表达式验证手机号、邮箱、身份证号等
Laravel怎么配置不同环境的数据库_Laravel本地测试与生产环境动态切换【方法】
如何在腾讯云免费申请建站?
JavaScript 输出显示内容(document.write、alert、innerHTML、console.log)
Laravel与Inertia.js怎么结合_使用Laravel和Inertia构建现代单页应用
如何构建满足综合性能需求的优质建站方案?
如何打造高效商业网站?建站目的决定转化率
邀请函制作网站有哪些,有没有做年会邀请函的网站啊?在线制作,模板很多的那种?
ChatGPT常用指令模板大全 新手快速上手的万能Prompt合集

