c#反射和特性

文章目录

  • 反射和特性
    • 元数据和反射
    • Type类
    • Assembly类
    • 特性
      • Obsolete特性【弃用】
      • conditional特性
        • condation默认的环境配置
      • condation自定义参数
      • condation&#if
        • 引子
        • 总结
      • conditional使用多个标识符【或逻辑】
        • 总结
      • condation实现'与'逻辑
        • 总结

反射和特性

元数据和反射

  • 程序是用来处理数据的,文本和特性都是数据,而我们程序本身(类的定义和BCL中的类)这些也是数据。(BCL-BasicClassLib基础类库)
  • 有关程序及其类型的数据被称为元数据(metadata),它们保存在程序的程序集中。
  • 程序在运行时,可以查看其它程序集或其本身的元数据。一个运行的程序查看本身的元数据或者其他程序集的元数据的行为叫做反射。【可以理解为反向映射】
  • 一个解决方案可以包含多个项目,而每个项目就是一个程序集。
    程序集基本上只是一个DLL或EXE文件。它包含IL代码和描述该DLL或EXE中的代码的类型信息。它也可以包含很多其他内容,但是对于初学者来说,只需将其视为DLL即可。
  • Type类位于System.Reflection命名空间下。
  • 如何使用Type类来反射数据,以及如何使用特性来给类型添加元数据。

Type类

  • 预定义类型(intlong和string等),BCL中的类型(ConsAe,lEnumerable等)和程序员自定义类型(MyClass,MyDel等)。每种类型都有自己的成员和特性。
  • BCL声明了一个叫做Type的抽象类,它被设计用来包含类型的特性。使用这个类的对象能让我们获取程序使用的类型的信息。
  • 由于Type是抽象类,因此不能利用它去实例化对象。关于Type的重要事项如下:对于程序中用到的每一个类型,CLR都会创建一个包含这个类型信息的Type类型的对象。
  • 程序中用到的每一个类型都会关联到独立的Type类的对象。不管创建的类型有多少个示例,只有一个Type对象会关联到所有这些实例。
using System;
using System.Reflection;

namespace test07
{
    internal class Program
    {
        //反射
        public static void Main(string[] args)
        {
            //type
           //每个类对应一个type对象,抽象类是需要我们创建
           //两种获取方式
           //方式一:typeof(类名)
           Type t = typeof(MyClass);
           //方法二:通过实例的对象
           var myClass = new MyClass();
           var type = myClass.GetType();
           Console.WriteLine(type.Name);
           Console.WriteLine("========");
           //获取MyClass的命名空间信息
           Console.WriteLine(t.Namespace);
           //获取MtClass的类名
           Console.WriteLine(t.Name);
           //获取MyClass的程序集
           Console.WriteLine(t.Assembly); 
           //获取MyClass[public修饰的]字段 将字段封装为FileInfo
           FieldInfo[] fis = t.GetFields();
           foreach (FieldInfo fi in fis)
           {
               Console.WriteLine(fi.Name);
           }
           //获取所有的属性
            PropertyInfo[] pis = t.GetProperties();
            foreach (PropertyInfo pi in pis)
            {
                Console.WriteLine(pi.Name);
            }
            //获取[public修饰的]方法
            MemberInfo[] mis = t.GetMethods();
            foreach (var mi in mis)
            {
                Console.WriteLine(mi.Name);
            }
        }
    }
}

c#反射和特性_第1张图片

Assembly类

c#反射和特性_第2张图片
c#反射和特性_第3张图片

特性

  • 特性(attribute)是一种允许我们向程序的程序集增加元数据的语言结构。它是用于保存程序结构信息的某种特殊类型的类。
    • 将应用了特性的程序结构叫做目标
    • 设计用来获取和使用元数据的程序(对象浏览器)叫做特性的消费者
    • MET预定了很多特性,我们也可以声明自定义特性
      c#反射和特性_第4张图片

Obsolete特性【弃用】

一个程序可能在其生命周期中经历多次发布,而且很可能延续多年。在程序生命周期的后半部分,程序员经常需要编写类似功能的新方法替换老方法。处于多种原因,你可能不再使用哪些调用过时的旧方法的老代码。而只想用新编写的代码调用新方法。旧的方法不能删除,因为有些旧代码也使用的旧方法,那么如何提示程序员使用新代码呢?可以使用Obsolete特性将程序结构标注为过期的,并且在代码编译时,显示有用的警告信息。
————————————————
版权声明:本文为CSDN博主「WhiteJunior」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lym940928/article/details/80550416

 internal class Program
    {
    	//Obsolete特性用来表示一个方法被弃用了,并显示有用的警告信息
        //默认参数是false,表示不推荐使用,但并不会设置为错误
        //如果参数为true,就是设置为错误
        [Obsolete("这个方法已经弃用了,请使用最新的NewTest方法",true)]//特性:弃用
        static void Test()
        {
            Console.WriteLine("Test");
        }
        static void NewTest()
        {
            Console.WriteLine("NewTest");
        }
    
        public static void Main(string[] args)
        {
            //已经弃用了,调用会报错
            //Test();
            NewTest();
        }
    }

conditional特性

condation默认的环境配置

  • Release/Debug
 internal class Program
    {
        //参数定义了再debug环境下调用方法
        [Conditional("DEBUG")]
        static void ShowMessage(string str)
        {
            Console.WriteLine(str);
        }
        public static void Main(string[] args)
        {
            ShowMessage("Start of Main");
            
            ShowMessage("Running in Main");
            
            ShowMessage("end of Main");
        }
    }

c#反射和特性_第5张图片

condation自定义参数

  • condation除了使用默认的环境配置,还可以通过宏定义来控制是否调用

  • 方式一:在程序的第一行定义编译条件

#define UseFlag //需要写到第一行
internal class Program
    {
        [Conditional("UseFlag")]
        static void Message()
        {
            Console.WriteLine("调用了宏定义参数的方法!");
        }
        public static void Main(string[] args)
        {
             Message();
        }
    }

c#反射和特性_第6张图片

  • 方式二:在项目的properties里面配置
    c#反射和特性_第7张图片
  • 测试结果
    c#反射和特性_第8张图片

condation&#if

引子

  • 测试一
#define Use
using System;
using System.Diagnostics;
[Conditional("Use")]
public static void Test1()
{
    Console.WriteLine("通过Conditional成功调用!");
}
 public static void Test2()
{
  #if Use
      Console.WriteLine("通过#if成功调用!");
  #endif
}
public static void Main(string[] args)
{
    Test1();
    Test2();
}
  • 测试结果
    c#反射和特性_第9张图片
  • 测试二
    • 在properties中配置
      c#反射和特性_第10张图片
  • 测试结果
    在这里插入图片描述

总结

  • 测试结果相同。但写法并不等价!用Conditional属性的方式,方法是否生效是取决于调用方,而用#if方式,Test方法是否生效是取决于方法定义所在的程序集。

conditional使用多个标识符【或逻辑】

  • 只定义了一个宏
    在这里插入图片描述
[Conditional("Use"),Conditional("apply")]
public static void Test1()
{
   Console.WriteLine("通过Conditional成功调用!");
}
[Conditional("Use")][Conditional("apply")]
public static void Test3()
 {
     Console.WriteLine("通过Conditional成功调用!");
 }

在这里插入图片描述

总结

  • 本质是‘或’逻辑

condation实现’与’逻辑

[Conditional("Use")]
public static void Test1()
{
    Console.WriteLine("通过Conditional成功调用!");
}

[Conditional("apply")]
public static void Test3()
{
    Test1();
}
public static void Main(string[] args)
{
    Test3();
}

总结

  • Conditional的好处:让代码更加具有阅读性。
  • #if…#elif…#else…#endif这种逻辑性很强的代码,建议采用#if的写法,代码可读性更强。

你可能感兴趣的:(CSharp,c#,.net,开发语言)