返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C#反射机制介绍
  • 506
分享到

C#反射机制介绍

2024-04-02 19:04:59 506人浏览 薄情痞子
摘要

先看下面一个动物点名系统的简单例子: 有一个Animal的抽象动物父类,里面定义了Name、Age两个属性和一个Shout()方法,Animal类定义如下: using System

先看下面一个动物点名系统的简单例子:

有一个Animal的抽象动物父类,里面定义了Name、Age两个属性和一个Shout()方法,Animal类定义如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Animal
{
    /// <summary>
    /// 抽象父类
    /// </summary>
    public abstract class Animal
    {
        /// <summary>
        /// Name属性
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// Age属性
        /// </summary>
        public int Age { get; set; }

        /// <summary>
        /// Shout抽象方法
        /// </summary>
        public abstract void Shout();
    }
}

分别定义Cat、Dog类继承自Animal类,Cat类定义如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Animal
{
    public class Cat :Animal
    {
        /// <summary>
        /// 构造函数初始化
        /// </summary>
        public Cat()
        {
            base.Name = "汤姆";
            base.Age = 2;
        }

        public override void Shout()
        {
            Console.WriteLine("喵喵喵,我是{0},今年{1}岁",
                base.Name,base.Age);
        }
    }
}

Dog类定义如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Animal
{
    public class Dog : Animal
    {
        /// <summary>
        /// 构造函数初始化
        /// </summary>
        public Dog()
        {
            base.Name = "布鲁斯";
            base.Age = 3;
        }

        public override void Shout()
        {
            Console.WriteLine("汪汪汪,我是{0},今年{1}岁",
                base.Name, base.Age);
        }
    }
}

应用场景:在一个控制台程序中,输入具体的动物的类型,根据输入的动物类型,输出Name、Age和Shout()方法,使用传统方式实现的代码如下:

using Animal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;


namespace ReflectionCon
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("请录入动物类型:");
            string type = Console.ReadLine().Trim();

            Animal.Animal a = null;
            switch (type)
            {
                case "cat":
                    a = new Cat();
                    a.Shout();
                    break;
                case "dog":
                    a = new Cat();
                    a.Shout();
                    break;
            }
            Console.ReadKey();
        }
    }
}

程序运行结果如下:

那么问题来了:如果我们想要增加一个动物类型,那么就需要修改现有的代码,在switch里面增加判断。但是这种方式很不利于以后的维护,违反了开闭原则,每次增加一个动物类型的时候,都需要修改代码。那么有没有其他方式可以做到不用修改代码就可以实现呢?答案是肯定的,那就是使用我们接下来要讲的反射,先来了解一下什么是反射。

一、什么是反射

在讲解什么是反射之前,先来了解应用程序的结构。

程序代码在编译后生成可执行的应用,我们首先要了解这种可执行应用程序的结构。

应用程序结果分为应用程序域-程序集-模块-类型-成员几个层次,公共语言运行时(CLR)加载器管理应用程序域,这种管理包括将每个程序集加载到相应的应用程序域以及控制每个程序集中类型层次结构的内存布局。

程序集包含模块,而模块包含类型,类型又包含成员,反射则提供了封装程序集、模块和类型的对象。我们可以使用反射动态地创建类型的实例,将类型绑定到现有对象或从现有对象中获取类型,然后调用类型的方法或访问其字段和属性。

那么究竟什么是反射呢?

反射(Reflection)是.net中的重要机制,可以在运行时获得.NET中每一个类型(包括类、结构、委托、接口和枚举等)的成员,包括方法、属性、事件、以及构造函数等。还可以获得每个成员的名称、限定符和参数等。有了反射,即可对每一个类型了如指掌。如果获得了构造函数的信息,即可直接创建对象,即使这个对象的类型在编译时还不知道。

二、反射的用途

1、使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。

2、使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。

3、使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如public或private)和实现详细信息(如abstract或virtual)等。使用Type的GetConstructors()或GetConstructor()方法来调用特定的构造函数。

4、使用MethodInfo了解方法的名称,返回类型、参数、访问修饰符(如public或private)和实现详细信息(如abstract或virtual)等。使用Type的GetMethods()或GetMethod()方法来调用特定的方法。

5、使用FiledInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。

6、使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。

7、使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。

8、使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。

三、反射用到的命名空间及主要类

1、命名空间

System.Reflection
System.Type
System.Reflection.Assembly

2、反射用到的主要类

Type类:该类位于System.Type命名空间下面,通过这个类可以访问任何给定数据类型的信息。

Assembly类:该类位于System.Reflection.Assembly命名空间下面,通过这个类可以访问给定程序集的信息,或者把这个程序集加载到程序中。

四、Type类

Type类位于System.Type命名空间下面,通过这个类可以访问关于任何数据类型的信息。

我们以前把Type看作一个类,但它实际上是一个抽象的基类。只要实例化了一个Type对象,实际上就实例化了Type的一个派生类。尽管一般情况下派生类只提供各种Type方法和属性的不同重载,但是这些方法和属性返回对应数据类型的正确数据,Type有与每种数据类型对应的派生类。

它们一般不添加新的方法或属性。通常,获取指向任何给定类型的Type引用有3种常用方式:

1、使用GetType()方法,所有的类都会从System.Object继承这个方法

string v = "abc";
Type type = v.GetType();

2、使用Type类的静态方法GetType()

Type type2 = Type.GetType("System.string", false, true);

3、使用C#的typeof运算符,这个运算符的参数是类型的名称(但不放在引号中)

var t = typeof(string);

运行结果:

注意:在一个变量上调用GetType()方法,不是把类型的名称作为其参数。但要注意,返回的Type对象仍只与该数据类型相关。如果引用了一个对象,但不能确保该对象实际上是哪个类型的实例,这个方法就很有用。

4、Type类的属性

由Type实现的属性可以分为下述三类:

1)许多属性都可以获取包含与类相关的各种名称的字符串

2)属性还可以进一步获取Type对象的引用,这些引用表示相关的类

3)许多Boolean 属性表示这个类型是一个类、还是一个枚举等。这些属性包括IsAbstract、IsArray、IsClass、IsEnum、IsInterface、IsPointer、IsPrimitive(一种预定义的基本数据类型)、 IsPublic、IsSealed和IsValueType

5、Type类的方法

System.Type类的大多数方法都用于获取对应数据类型的成员信息:构造函数、属性、方法和事件等。它有许多方法,但它们都有相同的模式。

例如,有两个方法可以获取数据类型的方法信息:GetMethod() 和 GetMethods()。GetMethod()方法返回System.Reflection.MethodInfo对象的一个引用,其中包含一个方法的信息。GetMethods()返回这种引用的一个数组。其区别是GetMethods()返回所有方法的信息,而GetMethod()返回一个方法的信息,其中该方法包含特定的参数列表。这两个方法都有重载方法,该重载方法有一个附加的参数,BindingFlags枚举值,表示应返回哪些成员,例如,返回公有成员、实例成员和静态成员等。

Type的成员方法:

注意:GetMember() 和 GetMembers()方法返回数据类型的一个或所有成员的信息,这些成员可以是构造函数、属性和方法等。最后要注意,可以调用这些成员,其方式是调用Type的InvokeMember()方法,或者调用MethodInfo, PropertyInfo和其他类的Invoke()方法。

五、Assembly类

Assembly类在System.Reflection名称空间中定义,它允许访问给定程序集的元数据,它也包含可以加载和执行程序集(假定该程序集是可执行的)的方法。与Type类一样,Assembly类包含非常多的方法和属性。

在使用Assembly实例做一些工作前,需要把相应的程序集加载到正在运行的进程中。为此,可以使用静态成员Assembly.Load()或Assembly.LoadFrom()这两个方法的区别是:

Load()方法的参数是程序集的名称,运行库会在各个位置上搜索该程序集,试图找到该程序集,这些位置包括本地目录和全局程序集缓存。使用Load()方法前要添加程序集的引用。

LoadFrom()方法的参数是程序集的完整路径名,它不会在其他位置搜索该程程序集。

例如:

Assembly assembly1 = Assembly.Load("Animal");
Assembly assembly1 = Assembly.LoadFrom(@"D:\Study\Practice\Animal.dll");

这两个方法都有许多其他重载版本,它们提供了其他安全信息。加载了一个程序集后,就可以使用它的各种属性进行查询,例如,查找它的全名:

string name = assembly1.FullName;

Assembly类的一个功能是它可以获得在相应程序集中定义的所有类型的详细信息,只要调用Assembly以GetTypes()方法,它就可以返回一个包含所有类型的详细信息的Type类型的引用数组:

Type[] types = assembly.GetTypes();
foreach (Type definedType in types)
(
  //处理代码
)

六、使用反射实现上面的程序

经过上面的讲解,相信大家对反射有一定的了解了,下面将会使用反射实现开篇提到的应用场景,代码如下:

using Animal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;


namespace ReflectionCon
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("请录入动物类型:");
            string type = Console.ReadLine().Trim();

            // 创建程序集对象,静态加载Animal程序集  前提:需要先添加对Animal程序集的引用
            Assembly assembly = Assembly.Load("Animal");
            // 获取程序集中的类型(在这里指的就是Animal里面的类:即Cat、Dog、Pig、Bird类)
            Type[] types = assembly.GetTypes();
            foreach (Type t in types)
            {
                // t.Name表示类名(即Cat、Dog、Pig、Bird)
                if (type == t.Name.ToLower())
                {
                    // 找到Shout方法
                    MethodInfo m = t.GetMethod("Shout");
                    // 创建对象
                    object o = Activator.CreateInstance(t);

                    // 找属性
                    PropertyInfo[] para = t.GetProperties();
                    // 遍历属性
                    foreach (PropertyInfo p in para)
                    {
                        // 输出属性的名字 即:Name和Age
                        //Console.WriteLine(p.Name);
                        if (p.Name == "Name")
                        {
                            // 给属性赋值
                            p.SetValue(o, "张三", null);
                        }
                        if (p.Name == "Age")
                        {
                            // 获取o对象的属性为p的属性值并加10
                            int age = Convert.ToInt32(p.GetValue(o)) + 10;
                            // 给属性赋值
                            p.SetValue(o, age, null);
                        }
                    }

                    // 调用方法
                    m.Invoke(o, null);
                }
            }

            Console.ReadKey();
        }
    }
}

运行程序:

如果新增加一个动物类,只需要实现Animal抽象父类即可,而主程序不需要修改。

七、反射的优缺点

1、反射的优点

1)、反射提高了程序的灵活性和扩展性。
2)、降低耦合性,提高自适应能力。
3)、它允许程序动态创建和控制任何类的对象,无需提前硬编码目标类。适用在程序集不固定的地方,通常和配置文件一起使用。

2、反射的缺点

1)、性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。
2)、使用反射会模糊程序内部逻辑;程序员希望在源代码中看到程序的逻辑,反射却绕过了源代码的技术,因而会带来维护的问题,反射代码比相应的直接代码更复杂。

到此这篇关于C#反射机制的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持编程网。

--结束END--

本文标题: C#反射机制介绍

本文链接: https://lsjlt.com/news/141538.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C#反射机制介绍
    先看下面一个动物点名系统的简单例子: 有一个Animal的抽象动物父类,里面定义了Name、Age两个属性和一个Shout()方法,Animal类定义如下: using System...
    99+
    2024-04-02
  • Java反射机制介绍
    1.通过反射,我们可以构建实例,得到成员变量的值,得到方法并调用。 还可以获得定义在成员变量、方法、方法参数上的注解。 接下来看代码实现,然后讲原理。 1)构建无参实例:通过反射调用...
    99+
    2024-04-02
  • java反射机制详细介绍
    一、什么是JAVA的反射机制(推荐:java视频教程)Java反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifie...
    99+
    2015-08-04
    java
  • Java反射机制的原理介绍
    这篇文章主要介绍“Java反射机制的原理介绍”,在日常操作中,相信很多人在Java反射机制的原理介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java反射机制的原理介绍”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-17
  • 对于java反射机制的详细介绍
    本文由java编程入门栏目为大家详细介绍java中的反射机制,希望可以帮助到对于此机制有所不懂的同学。java反射机制是运行状态中,对于任意一个类都能够知道这个类的所有属性和方法(包括私有的);对于任意一个对象,都能调用他的任意方法和属性;...
    99+
    2019-02-22
    java入门 java 反射机制
  • C#的反射机制是什么
    本篇内容介绍了“C#的反射机制是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!属性定制是.NET提供的一个非常棒的新特性之一,属性对于所...
    99+
    2023-06-17
  • Java 反射机制
    简介: Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个...
    99+
    2024-04-02
  • C++中怎么使用反射机制
    今天就跟大家聊聊有关C++中怎么使用反射机制,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。在Java编程中,我们经常要用到反射,通过反射机制实现在配置文件中的灵活配置, 但在C++编...
    99+
    2023-06-17
  • java的反射技术详细介绍
    本篇内容主要讲解“java的反射技术详细介绍”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“java的反射技术详细介绍”吧!反射的定义:审查元数据并收集关于它的类型信息的能力。下面介绍java的反...
    99+
    2023-06-17
  • Java反射使用的详细介绍
    文章目录 反射反射基本介绍反射获取类对象反射获取构造器对象反射获取成员变量对象反射获取方法对象 反射 反射基本介绍 反射概述: 反射认为类的每一个成份都是一个对象, 对于任何一个Class类,在"运行的时候"都可以直接得...
    99+
    2023-08-20
    java jvm 开发语言
  • JavaSE基础之反射机制(反射Class)详解
    目录一:反射机制概述二:反射Class1. 获取Class的三种方式 2. 通过反射实例化(创建)对象3. 通过读配置属性文件实例化对象4. 只让静态代码块执行5. 获取类...
    99+
    2024-04-02
  • Java反射机制详解
    目录类的声明周期不同阶段都可以获取类对象获取Class类对象的方式的场景class类对象的功能如何获取私有变量的值根据有无主方法判断进程和线程反射出现的背景(记住)反射出现的背景类的...
    99+
    2024-04-02
  • java 反射机制初探
    最近再看书时,书中使用了java的动态代理机制,随即在网上搜了些文章看了一下,既然有动态代理那就有静态代理,所谓静态代理,就是在你些的代理类中需要使用到具体的被代理类。而所谓动态代理,则不需要在代理类中使用到被代理类,根本不知道起要代理那个...
    99+
    2023-06-03
  • Java全面系统介绍反射的运用
    目录反射反射定义反射的基本运用1.获取类对象a.forName()方法b.直接获取c.getClass()方法d.getSystemClassLoader().loadClass()...
    99+
    2024-04-02
  • 手写PHP API框架(三)之反射介绍
    上一篇《手写PHP API框架之Composer的安装使用(二)》文章中我们介绍了Composer的安装使用,这一文我们来介绍一下有关反射的概念介绍。反射,直观理解就是根据到达地找到出发地和来源。 反射指在PHP运行状态中,扩展分析PHP程...
    99+
    2023-05-14
    php API 反射
  • Golang反射介绍及应用场景分析
    go 语言中的反射功能允许程序在运行时检查和修改类型的结构。通过使用 type、value 和 reflect.kind,我们可以获取对象的类型信息、字段值和方法,还可以创建和修改对象。...
    99+
    2024-04-03
    golang 反射
  • C#使用反射机制实现延迟绑定
    反射允许我们在编译期或运行时获取程序集的元数据,通过反射可以做到: ● 创建类型的实例● 触发方法● 获取属性、字段信息● 延迟绑定...... 如果在编译期使用反射,可通过如下2种...
    99+
    2022-11-13
    C# 反射机制 延迟绑定
  • 什么是java反射机制
    java:“一切即对象”,感觉java语言本身在不断践行着这句话。java反射机制的基础来源于一个Class类,我们可以通过这个类里面的方法来对每一个类进行读取、实例化等。对象表示或封装一些数据。一个类被加载后,jvm会创建一个对应该类的C...
    99+
    2019-08-24
    java入门 java 反射机制
  • java反射机制最详解
    目录java反射机制什么是反射?反射的功能:反射常用类:1.Class枚举类2.Constructor构造器3.Method方法类4.Field变量类反射运行指示图通过反射获取对象总结java反射机制 什么是反射? 在java开发中有一个...
    99+
    2020-08-07
    java java反射机制
  • java反射机制是什么
    这篇文章主要介绍了java反射机制是什么,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。Java的特点有哪些Java的特点有哪些1.Java语言作为静态面向对象编程语言的代表,...
    99+
    2023-06-14
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作