首页 > 编程语言 >C# 反射的定义和应用场景

C# 反射的定义和应用场景

时间:2023-05-26 12:23:12浏览次数:50  
标签:反射 Test3 场景 C# Type static var type public

 

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));  //值
    }
}

 

转自:https://www.cnblogs.com/yinghualuowu/p/16991373.html

 

标签:反射,Test3,场景,C#,Type,static,var,type,public
From: https://www.cnblogs.com/wugh8726254/p/17434403.html

相关文章

  • 用pycharm创建一个django框架
    用pycharm创建一个django框架注意解释器的选择和文件路径创建完django项目1.自动创建了一个templates目录(先删除)2.把settings里的TEMPLATES=[{'BACKEND':'django.template.backends.django.DjangoTemplates','DIRS':[BASE_DIR/'templates......
  • Vue3.3 的新功能的体验(下):泛型组件(Generic Component) 与 defineSlots
    上一篇说了DefineOptions、defineModel、Props的响应式解构和从外部导入类型这几个新功能,但是没有说Generic、defineSlots等,这是因为还没有完全搞清楚可以用在什么地方。折腾了几天终于弄清楚了。这还要从TS的泛型说起。泛型的目的和意义泛型仅仅只是表达传啥都行吗?当然......
  • CentOS7 防火墙设置
    配置文件所在路径: /usr/lib/firewalld/#默认的规则 /etc/firewalld/#自定义规则开放防火墙端口: #开放单个端口 firewall-cmd--zone=public--add-port=22/tcp--permanent #限制单个端口 firewall-cmd--zone=public--remove-port=22/tcp--permanent #......
  • C++外卖点餐系统[2023-05-26]
    C++外卖点餐系统[2023-05-26]选题九:外卖点餐系统7.基本要求:[1]编写一个外卖点餐系统,实现对客户、店铺、订单及配送人员等信息的管理。[2]客户信息包括:客户姓名、联系方式、地址等;店铺信息包括:其菜品和价格评分等;配送人员信息包括:姓名,联系方式、评分等:订单信息包括:编......
  • vue --version 显示的却是vue cli的版本号,为什么?
    vue--version显示的却是vuecli的版本号,为什么?如果您在运行vue--version命令时显示的是VueCLI的版本号,而不是Vue.js的版本号,那可能是因为您已经全局安装了VueCLI。VueCLI是一个用于快速搭建Vue.js项目的脚手架工具,它依赖于Vue.js并提供了许多额外的功能和工具......
  • 2万多条QQ签名论坛签名大全ACCESS\EXCEL数据库
    2万多条QQ签名论坛签名大全ACCESS数据库收录了感情,恋爱,哲理,诗词,个性等7类共20000余条的QQ签名或论坛签名,有些包含幽默搞笑也有些蕴含哲理。您可以从中选择自己喜欢的作为自己的签名。截图下方有显示“共有记录数”,截图包含了表的所有字段列。该数据提供ACCESS数据库文件(扩展名是......
  • Linux服务器安装Kokkos-core 和 Kokkos-kernel
    说明由于实验室项目原因,需要跑一个Gmres算法,之前弄过kokkos,就想在kokkos-kernels里跑现有的GMRES算法库在此记录自己的安装的过程,以及自己踩过的一些坑。1.准备工作从Kokkos官网下载Kokkos以及Kokkos-kernels:https://github.com/kokkos/kokkos.git--Kokkos-corehttps:......
  • Electron打包的时候路径存在中文出现的bug
    在打包electron的时候报了这条错误1Erroroutput:2!include:couldnotfind:"C:\Users\xxxx(这里是中文)\AppData\Local\Temp\t-TH3KzB\0-messages.nsh"3Errorinscript"<stdin>"online75--abortingcreationprocess这个报错意思是路径有中文存在,解析不到,完......
  • HTTP Client 调用 ODI Scenario
    HTTP-Client的官方实例如下:http://svn.apache.org/viewvc/httpcomponents/oac.hc3x/trunk/src/examples/FormLoginDemo.java?revision=604567&view=markup ODI官方文档中推荐HTTPURL方式调用Scenario部分描述:WiththeMetadataNavigatormodule,it......
  • 帆软finebi、瓴羊Quick BI等为代表的国产BI工具崛起
    近年来,中美贸易摩擦的不断升级,使得国内企业受到“特殊照顾”。国家为了减少对外依赖,加快自主创新的步伐,逐渐加大对国产产品的支持力度。在这种情况下,国产BI工具逐渐替代外国BI工具成为了企业数据分析的新选择。瓴羊QuickBI、帆软finebi等国产BI工具在数据可视化等能力方面表现不输......