首页 > 编程语言 >C# 反射以及实际场景使用

C# 反射以及实际场景使用

时间:2022-12-20 01:22:22浏览次数:51  
标签:反射 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));  //值
    }
}

 

参考链接

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

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

相关文章

  • SpringMVC传递json字符串,后台接口通过变量接收
    前景介绍在我们日常开发过程中,前台向后台传递参数一般是json或者form表单方式,并且最好统一一种传输方式,不建议json+form混合使用,但是由于form表单在数组结构下拼接比较......
  • [C++]LeetCode 1760 袋子里最少数目的球
    [C++]LeetCode1760.袋子里最少数目的球题目描述Difficulty:中等RelatedTopics:数组,二分查找给你一个整数数组nums,其中nums[i]表示第i个袋子里球的数目。......
  • pytorch 笔记之 model.eval() 和 with torch.no_grad()
    model.eval()负责改变batchnorm、dropout的工作方式,如在eval()模式下,dropout是不工作的。torch.no_grad()负责关掉梯度计算,节省eval的时间。只进行inference时,model.ev......
  • JDBC之ResultSet和元数据
    ResultSet从名字上就可以看到是结果集,表示的是查询出来的结果集。JDBC用ResultSet来封装结果集,查询结果表的对象。查询结果分为两种情况:单值单个结果,比如说SQL如下:s......
  • 多个 csv 文件拼接
    代码:importpandasaspdimportglobtarget_path='Dataset/target.csv'cat_list=glob.glob('Dataset/cat/*csv')forindex,cat_csvinenumerate(cat_list): d......
  • CS22计导复习笔记
    CS22计导复习笔记一家之言,仅供参考,以实际为准。有疑义,是你对。——LeeHero/*题量:8题*/【for循环.python程序设计】>eg.算e/pi>要求精简,不能重复计......
  • npm,cnpm,yarn,pnmp之间的区别
     一、npm1、由于版本号的影响,所以会造成版本不统一的情况给定一个版本号:主版本号.次版本号.补丁版本号,以下这三种情况需要增加相应的版本号:主版本号:当API发生改变,并......
  • Java Endorsed Standards Override Mechanism
    参考资料https://docs.oracle.com/javase/6/docs/technotes/guides/standards/介绍FromtimetotimeitisnecessarytoupdatetheJavaplatforminordertoinc......
  • weblogic上部署CXFwebservice 错误!
    转自https://www.pianshen.com/article/4737505565/发布到weblogic上,输入网址http://localhost:7002/CxfTest/ws/helloService?wsdl;能正常显示出xml1、但是在客户端调用......
  • leetcode-最长回文子串
    给你一个字符串s,找到s中最长的回文子串。如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。 示例1:输入:s="babad"输出:"bab"解释:"aba"同样是符合题意的答......