1 什么是反射

首先要复习一下C#的编译过程,可以解释为下图

其中dll/exe中,包括元数据(metadata)和IL(中间语言Intermediate Language)

另外还出现的其他名词:CLR(公共语言运行时,Common Language Runtime)和JIT(实时编译器 Just in Time)

总结: 一个运行的程序查看本身的元数据或其他程序元数据的行为称之为反射

再配合 C# 命名空间和程序集 小记 中的图,来一层层的获取里面的数据

2 读取和使用Assembly

可以使用以下方式获取到Assembly

// See https://aka.ms/new-console-template for more information
using System.Reflection; var assembly = Assembly.Load("Reflection"); //Assembly.LoadFile();
//Assembly.LoadFrom(); Console.Read();

2.1 Assmbly实际使用

个人使用Assmbly有以下场景

2.1.1 当程序集存在资源文件时

项目因为存在贴牌,是通过XML文件配置的,因为平时对配置文件管控不足,所以需要和XML嵌入到项目内,一来防止丢失,二来是为了以后通过更新变更配置

var assembly = Assembly.Load("DesktopFramework.Start");

var file = $"DesktopFramework.Start.TemplateFiles.Config.{filename}.xml";

using (var stream = assembly.GetManifestResourceStream(file))
{
if (stream != null)
{
var doc = new XmlDocument();
doc.Load(stream);
//处理文件
}
}

2.1.2 动态加载dll文件

相信很多人都用过Cefsharp,其中对x64和x86的加载由以下代码实现

AppDomain.CurrentDomain.AssemblyResolve += Resolver;

private static Assembly Resolver(object sender, ResolveEventArgs args)
{
if (args.Name.StartsWith("CefSharp"))
{
var assemblyName = args.Name.Split(new[] { ',' }, 2)[0] + ".dll";
var archSpecificPath = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
Environment.Is64BitOperatingSystem ? "x64" : "x86",
assemblyName); return File.Exists(archSpecificPath)
? Assembly.LoadFile(archSpecificPath)
: null;
} return null;
}

2.1.3 获取版本号

烂大街的写法:Assembly.GetExecutingAssembly().GetName().Version.ToString();

3 Type

Type是抽象类,使用这个对象能让我们获取程序的类型信息

  • 对于程序的每一个类型,CLR都会创建一个包含这个类型信息的Type类型的对象
  • 每一个类型都会关联到独立的Type类的对象
  • 不管创建的类型有多少个实例,都只有一个Type对象会关联到所有这些实例

3.1 获取Type

获取Type有两种办法 GetTypes()和typeof

假设存在类Test1 Test2

namespace Reflection
{
public class Test1
{ } public class Test2
{ }
}
using Reflection;
using System.Reflection; namespace AssemblyReflection
{
internal static class GetReflection
{
public static void GetTypes()
{
var assembly = Assembly.Load("Reflection");
foreach (var value in assembly.GetTypes())
{
Console.WriteLine(value.Name);
} /*
* 输出
*Test1
*Test2
*/
} public static void GetTypeName()
{
Type type = typeof(Test1);
Console.WriteLine(type.Name);
}
}
}

4 构造函数和方法

4.1 构造函数和创建实例

在说构造函数之前,先看看怎么通过type构造实例。首先是通过 Activator.CreateInstance(type),然后通过 type.GetConstructor寻找构造方法,再通过Invoke调用。

public static void CreateInstance()
{
//对默认构造函数
Type type = typeof(Test3);
var instance1 = Activator.CreateInstance(type) as Test3;
Console.WriteLine(instance1?.PublicValue);
}
public static void GetConstructInfo()
{
Type type = typeof(Test3);
ConstructorInfo? publicDefaultConstructor = type.GetConstructor(Type.EmptyTypes);
var instance = publicDefaultConstructor?.Invoke(null);
}

4.2 方法调用和重载方法

有了上面获取构造方法的例子,那么去获取方法也是比较容易。存在一种场景,比如和调用方约定方法名和函数签名,那么调用方只需要使用方法名和参数就可以调用。

首先给出一个类,仅仅函数签名不一样却存在多个方法。

public class Test3
{
private string PrivateValue { get; set; } public string PublicValue { get; set; } = "1"; public bool PublicBoolValue { get; set; } public Test3()
{ } static Test3()
{ } public Test3(string value)
{
PublicValue = value;
} public Test3(string value,bool boolValue)
{
PublicValue = value;
PublicBoolValue = boolValue;
} private Test3(string privateValue,string publicValue)
{
PrivateValue = privateValue;
PublicValue = publicValue;
} public void OutPut()
{
Console.WriteLine(PublicValue);
} public void OutPut(int param)
{
PublicValue += param;
Console.WriteLine(PublicValue);
} public void OutPut(bool param)
{
PublicBoolValue = param;
Console.WriteLine(PublicValue);
}
}

按照调用构造方法的模式,很快就可以得到以下代码,很可惜,这段代码无法使用,原因是上述给的方法存在重载,无法通过普通的方式反射得到对应的方法。

public static void Invoke()
{
Type type = typeof(Test3);
var instance1 = Activator.CreateInstance(type) as Test3;
var method = type.GetMethod("OutPut");
method?.Invoke(instance1, null);
}

我们对寻找方法的代码稍作修改:var method = type.GetMethod("OutPut",new []{typeof(bool)});,这样就可以得到一个指定的方法。

还可以通过 GetParameters获取方法参数。

5 GetFields

有些时候,某些字段是通过 const static保存下来的,需要通过反射得到它们。假设存在一个类

public class GetFields
{
public static string Key1 = "1";
public const string Key2 = "2";
}

5.1 BindingFlags

反射当中很多都用到了BindingFlags。可以通过命名知道我们要获取Public的字段,那么

public static void GetClassFields()
{
FieldInfo[] fields = typeof(Test4).GetFields(BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.Static); foreach (FieldInfo item in fields)
{
string name = item.Name; //名称
object? value = item.GetValue(typeof(Test4)); //值
}
}

参考链接和文件代码

C#反射中的GetConstructor与GetConstructors构造函数参数的获取

https://github.com/yinghualuowu/blogsCodeSimple/tree/main/AssemblyReflection

C# 反射以及实际场景使用的更多相关文章

  1. java反射的运用场景

    1.反射的好处是:可以在运行时确认对象以及方法. 2.下面举个简单的例子来说下反射的运用场景: 假如一款游戏有一个配置文件,配置文件里有个renderType设置了游戏启动时调用哪个RenderHan ...

  2. 简单模拟Java中反射的应用场景

    有人说Java是一门静态语言.那么何为静态语言,动态语言又是什么? 1.动态语言 是一类在运行时可以改变其结构的语言:例如新的函数.对象.甚至代码可以 被引进,已有的函数可以被删除或是其他结构上的变化 ...

  3. Java反射机制使用场景

    import java.io.*; import java.util.Properties; /*问题描述:存在一个主板--已经定义好,不想修改其代码,还想在主板上面增加一些其他功能? *问题解决方法 ...

  4. C# 反射、使用场景

    创建一个 Console 控制台应用程序, 1. 创建一个 Project 类 public class Project { public int ID { get; set; } public st ...

  5. 03.反射--01【反射机制】【反射的应用场景】【Tomcat服务器】

    https://blog.csdn.net/benjaminzhang666/article/details/9408611 https://blog.csdn.net/benjaminzhang66 ...

  6. Java反射机制的适用场景及其利与弊 ***

    一.反射的适用场景是什么? 1).Java的反射机制在做基础框架的时候非常有用,有一句话这么说来着:反射机制是很多Java框架的基石.而一般应用层面很少用,不过这种东西,现在很多开源框架基本都已经给你 ...

  7. Java反射详解:入门+使用+原理+应用场景

    反射非常强大和有用,现在市面上绝大部分框架(spring.mybatis.rocketmq等等)中都有反射的影子,反射机制在框架设计中占有举足轻重的作用. 所以,在你Java进阶的道路上,你需要掌握好 ...

  8. 长篇图解java反射机制及其应用场景

    一.什么是java反射? 在java的面向对象编程过程中,通常我们需要先知道一个Class类,然后new 类名()方式来获取该类的对象.也就是说我们需要在写代码的时候(编译期或者编译期之前)就知道我们 ...

  9. 在 .NET 4.5 中反射机制的变更

    反射机制(Reflection)通常会涉及到3中场景: 运行时反射 场景:可以检索已加载程序集.类型.对象.实例和方法调用的元数据(Metadata). .NET 支持情况:支持 仅供静态分析的反射 ...

  10. Unity3D ShaderLab 简单的立方体图反射

    Unity3D ShaderLab 简单的立方体图反射 反射是着色器模拟现实环境的一个关键因素,它能使我们的着色器渲染效果更加具备视觉冲击,因为他利用了我们周围的环境, 让着色器反射外界的场景信息并将 ...

随机推荐

  1. HttpServletRequest获取header参数 sign

    HttpServletRequest获取header参数 sign //从请求头中获取参数 private static Map<String, String> getHeaders(Ht ...

  2. 中国电信登录RSA算法+分析图文

    Tips:当你看到这个提示的时候,说明当前的文章是由原emlog博客系统搬迁至此的,文章发布时间已过于久远,编排和内容不一定完整,还请谅解` 中国电信登录RSA算法+分析图文 日期:2016-9-30 ...

  3. C++操作符重载(operator)

    c++操作符 例如-=+*/等,甚至包括,<<等都是操作符.c++特色之一就是给予完全重构和重载操作符(Java不可以,c#操作部分). 例子入手 假设一个结构体,定义如下 struct ...

  4. Linux unset命令用法

    Linux unset命令用于删除变量或函数. unset为shell内建指令,可删除变量或函数 参数: -f 仅删除函数 -v 仅删除变量 [root@localhost ~]# yangzc=&q ...

  5. 使用 Spring 实现控制反转和依赖注入

    使用 Spring 实现控制反转和依赖注入 概述 在本文中,我们将介绍IoC(控制反转)和DI(依赖注入)的概念,以及如何在Spring框架中实现它们. 什么是控制反转? 控制反转是软件工程中的一个原 ...

  6. R语言遍历文件夹求取其中所有栅格文件的平均值

      本文介绍基于R语言中的raster包,遍历读取多个文件夹下的多张栅格遥感影像,分别批量对每一个文件夹中的多个栅格图像计算平均值,并将所得各个结果栅格分别加以保存的方法.   其中,本文是用R语言来 ...

  7. 工控必备!NXP i.MX 8M Mini开发板规格书资料分享,高性能低功耗!

    1 核心板简介 创龙科技SOM-TLIMX8-B是一款基于NXP i.MX 8M Mini的四核ARM Cortex-A53 + 单核ARM Cortex-M4异构多核处理器设计的高端工业级核心板,A ...

  8. OpenBMB × Hugging Face × THUNLP,联袂献上经典大模型课

    这个夏天,THUNLP 携手 Hugging Face 和 OpenBMB,推出 大模型公开课第二季.在大模型公开课第二季中,将有全球知名开源社区 OpenBMB X Hugging Face 梦幻联 ...

  9. 基于Bootstrap Blazor开源的.NET通用后台权限管理系统

    前言 今天大姚给大家分享一个基于Bootstrap Blazor开源的.NET通用后台权限管理系统,后台管理页面兼容所有主流浏览器,完全响应式布局(支持电脑.平板.手机等所有主流设备),可切换至 Bl ...

  10. C#多态性学习,虚方法、抽象方法、接口等用法举例

    1. 多态性定义   C#中的多态性是OOP(面向对象编程)的一个基本概念,它允许一个对象在不同情况下表现出不同的行为,以增强代码的可重用性和灵活性.   根据网上的教程,我们得知C#多态性分为两类, ...