C#实现反射

本文详细介绍了如何使用C#的反射机制来构建对象、查看类的字段和方法,并允许用户交互调用方法。通过加载.dll文件,根据components.txt文件创建对象数组,然后利用反射展示类信息,包括字段和方法。用户可以选择类和方法进行操作,系统还能随机执行对象的方法,展示了反射在系统演化中的应用。此外,代码示例中包含了图形类库的定义,如矩形、三角形、球体和椭圆等。
摘要由CSDN通过智能技术生成

C#实现反射

一、引言

任务

2.2 构建一个components.txt文件,每行代表一个类(比如形状类Shape)的名字(这些类可以来自系统库,或者自己构造);程序逐行扫描该文件,构建对应的类的对象。要求:

1)并把这些对象放到数组中;

  1. 列出每个类的字段、方法;

3)让用户选择,使得用户可以调用所需要的方法(操作)

4)系统随机选择对象(比如形状),随机的执行其操作。从而看系统演化。可能的话,进行界面展示

二、实验环境

Visual stdio 2017
Windows窗体应用

三、实验过程

思路

  1. 创建一个类,用于后续反射其信息
  2. 命令行编译命令 使 .cs生成.dll文件
  3. 构建一个components.txt文件
  4. 利用反射查看成员信息

1.创建一个类

内容包括各个shape的面积和周长计算公式等内容(后续有完整代码)

2.命令行编译命令 使 .cs生成.dll文件

命令行编译命令

步骤:
在这里插入图片描述
然后逐行输入以下命令语句

path C:\Windows\Microsoft.NET\Framework\v2.0.50727

cd C:\Users\lenovo\source\repos\shiyan3\shiyan3

csc/target:library Graphic.cs

path C:\Windows\Microsoft.NET\Framework\v2.0.50727里有对C#进行编译的程序csc.exe)

(cd C:\Users\lenovo\source\repos\shiyan3\shiyan3 是指项目的位置)但由于此路径在我的电脑上,所以别的电脑打开不一定能运行此代码Orz)

(csc/target:library Graphic.cs ->”csc/target:library”是常用的模块名 ,该命令让编译器创建一个动态链接库(DLL),而不是一个可执行文件(EXE))

构建一个components.txt文件

构components.txt文件
在这里插入图片描述
实验要求是构建一个components.txt文件,每行代表一个类.程序逐行扫描该文件,构建对应的类的对象,所以在其中写入:

Rectangle

Triangle

Sphere

Ellipse
读取文件:

//程序逐行扫描components.txt文件,构建对应的类的对象
 string path = "components.txt";
 FileStream FFLIE = File.OpenRead(path);
 StreamReader STREAMR = new StreamReader(FFLIE, Encoding.Default);
 FFLIE.Seek(0, SeekOrigin.Begin);

4.利用反射查看成员信息

4.1

接下来,在Program.cs中, 利用反射,来读取字段的字段、方法等

首先加入内存空间
using System.Reflection;

using System.Collections;

using System.IO;

在这里插入图片描述

4.2

反射具体知识点:

反射是一种机制,通过这种机制可以知道一个未知类型的类型信息。

既然叫反射,就像拿一面透视镜,它可以反射出我们本不能看见信息.

反射中常用的类
1.Type类

System.Reflection是反射的命名空间,而Type类为System.Reflection功能的根,也是访问元数据的主要方式。

Type类表示类型声明,包括类类型、接口类型、数组类型、值类型、枚举类型、类型参数、泛型类型定义,以及开放或封闭构造的泛型类型。

得到一个Type实例的三种方法如下:

(1)使用System.Object.GetType(),例如:

Person pe=new Person(); //定义pe为person类的一个对象

Type t=pe.GetType(); //我的代码用的是这个方法Type fanshelei = gelei.GetType();;

这样t为pe的Type对象。

(2)使用System.Type.GetType()静态方法,参数为类型的完全限定名。例如:

Type t=Type.GetType(“MyNs.Person”);

其中,MyNs.Person为MyNs命名空间中的Person类,这样t为该类的Type对象。

(3)使用typeof运算符,例如:

Type t=typeof(Person);

其中Person为一个类,这样t为该类的Type对象。

2.System.Reflection反射命名空间

System.Reflection反射命名空间包含提供加载类型、方法和字段的有组织的视图的类和接口,具有动态创建和调用类型的功能。其中主要的类及其功能如下:

Assembly类:通过它可以加载、了解和操作一个程序集。

//此次作业代码用到 :

Assembly assembly = Assembly.LoadFrom(“Graphic.dll”);//加载程序集(cs文件生成.dll文件,.dll文件是一个程序集)

Console.WriteLine(“name of assembley:” + assembly.GetName());//输出程序集的Name

AssemblyName类:通过它可以找到大量隐藏在程序集的身份中的信息,如版本信息、区域信息等。

ConstructorInfo类:用于发现构造函数及调用构造函数。通过对ConstructorInfo调用Invoke来创建对象,其中ConstructorInfo是由Type对象的GetConstructors或GetConstructor方法返回的。

EventInfo类:通过它可以找到事件的信息。

FieldInfo类:通过它可以找到字段的信息。//此次作业代码用到 FieldInfo[] ziduannum = fanshelei.GetFields();

MethodInfo类:通过它可以找到方法的信息。//此次作业代码用到 MethodInfo[] methodnum = fanshelei.GetMethods();

ParameterInfo类:通过它可以找到参数的信息。

PropertyInfo类:通过它可以找到属性的信息。

MemberInfo类:它是一个抽象基类,为EventInfo、FieldInfo、MethodInfo、PropertyInfo等类型定义了公共的行为。

Module类:用来访问带有多文件程序集的给定模块。

DefaultMemberAttribute类:定义某类型的成员,该成员是InvokeMember使用的默认成员。

步骤:通过反射输出用户所需要的查看的类的方法、字段信息。

先通过Type的GetType() 方法获取用户所需要的查看的类的Type对象mytype,然后用Type类的GetMethods()、GetFields()分别获取mytype对象的方法、字段并输出。程序如下:

由上述知Assembly类:通过它可以加载、了解和操作一个程序集。

Assembly assembly = Assembly.LoadFrom(“Graphic.dll”);//加载程序集(cs文件生成.dll文件,.dll文件是一个程序集)

​ Console.WriteLine(“name of assembley:” + assembly.GetName());//输出程序集的Name

在这里插入图片描述
GetType:返回一个指定类型的Type对象

MethodInfo:找到方法的信息

FieldInfo:找到字段的信息


   if (gelei != null)
       Console.WriteLine("<{0}>类名:{1}", classList.Count, fanshelei.Name);
   //列出每个类的字段、方法;
   MethodInfo[] methodnum = fanshelei.GetMethods();
   Console.WriteLine("  {0}的方法个数:{1}", fanshelei.FullName, methodnum.Length);
   for (int j = 0; j < methodnum.Length; j++)
   {
       Console.WriteLine("  ({0}){1}", j + 1, methodnum[j].Name);
   }
                   

   FieldInfo[] ziduannum = fanshelei.GetFields();
   Console.WriteLine("  {0}的字段个数:{1}", fanshelei.FullName, ziduannum.Length);
   for (int k = 0; k < ziduannum.Length; k++)
   {
       Console.WriteLine("  ({0}){1}", k + 1, ziduannum[k].Name);
   }

4.3让用户选择,使得用户可以调用所需要的方法(操作)

//让用户选择,使得用户可以调用所需要的方法(操作)
Console.Write(“请选择类对象<1-4>或退出0:”);
int leiduixiang = int.Parse(Console.ReadLine());


 //让用户选择,使得用户可以调用所需要的方法(操作)
     Console.Write("请选择类对象<1-4>或退出0:");
     int leiduixiang = int.Parse(Console.ReadLine());

     if (leiduixiang == 0)
         break;
     if (leiduixiang < 0 || leiduixiang > 4)
     {
         Console.WriteLine("输入错误!\n***********************");
         continue;
     }
     Type curtype = classList[leiduixiang - 1].GetType();
     MethodInfo[] methodnumss = curtype.GetMethods();
     Console.WriteLine("  {0}的方法个数:{1}", curtype.FullName, methodnumss.Length);
     for (int i = 0; i < methodnumss.Length; i++)
         Console.WriteLine("  ({0}){1}", i + 1, methodnumss[i].Name);
     Console.Write("请选择方法(except 4):");
     int nowfangfa = int.Parse(Console.ReadLine());
     object myshape = classList[leiduixiang - 1];
     if (nowfangfa < 1 || nowfangfa > 6 || nowfangfa == 4)
         Console.WriteLine("输入错误!\n***********************");
     else
         Console.WriteLine(myshape.GetType().Name + "——" + methodnumss[nowfangfa - 1].Name + ":" + methodnumss[nowfangfa - 1].Invoke(myshape, null) + "\n***********************" +
             "");

在这里插入图片描述

4.4

系统随机选择对象(比如形状),随机的执行其操作。从而看系统演化。可能的话,进行界面展示

case “1”😕/系统随机生成

DateTime结构类位于System命名空间中,DateTime值类型表示值范围在公元0001年1月1日午夜12:00:00到公元9999年12月31日晚上11:59:59之间的日期和时间。

Millisecond 获取此实例所表示日期的毫秒部分


   TimeSpan ttime = new DateTime() - new DateTime(1999,12, 3);
    float hm = ttime.Milliseconds;
    Random myrandom = new Random();
    int classNum = myrandom.Next(0, 3);
    object myobject = classList[classNum];//随机选择一个类


    int numfangfa;
    while (true)
    {
        numfangfa = myrandom.Next(1, 6);
        if (numfangfa != 4)
            break;
    }
    Type leixing = classList[classNum].GetType();
    MethodInfo[] methoddn = leixing.GetMethods();
    Console.WriteLine(leixing.Name + "——" + methoddn[numfangfa - 1].Name + ":" + methoddn[numfangfa - 1].Invoke(myobject, null) + "\n***********************");
    break;

代码会生成语句:Triangle——Perimeter:11.5440037453175
请添加图片描述

完整代码:

图形类

using System;
namespace csharp_exp4
{
    public class Rectangle//长方形
    {
        public const double PI = Math.PI;
        protected double x, y;
        public Rectangle() { }
        public Rectangle(double x1, double y1)
        {
            x = x1;
            y = y1;
        }
        public virtual double Area()//面积
        {
            return x * y;
        }
        public virtual double Perimeter()//周长
        {
            return (x + y) * 2;
        }
    }
    public class Triangle : Rectangle//等腰三角形
    {
        public Triangle(double x, double y) : base(x, y)//宽,高
        { }
        public override double Area()
        {
            return x * y / 2;
        }
        public override double Perimeter()
        {
            return Math.Sqrt(x * x / 4 + y * y) * 2 + x;
        }
    }
    public class Sphere : Rectangle//圆
    {
        public Sphere(double r, double y) : base(r, 0) { }
        public override double Area()
        {
            return PI * x * x;
        }
        public override double Perimeter()
        {
            return 2 * PI * x;
        }
    }
    public class ellipse : Rectangle//椭圆
    {
        public ellipse(double a, double b) : base(a, b) { }
        public override double Area()
        {
            return PI * x * y;
        }
        public override double Perimeter()
        {
            return 2 * PI * y + 4 * (x - y);
        }
    }

}

Program.cs


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

namespace shiyan3
{
    class Program
    {
        static void Main(string[] args)
        {
            Assembly assembly = Assembly.LoadFrom("Graphic.dll");//加载程序集:cs文件生成.dll文件,.dll文件是一个程序集
            Console.WriteLine("name of assembley:" + assembly.GetName());//程序集的 名称
            Type[] types = assembly.GetTypes();

            //程序逐行扫描components.txt文件,构建对应的类的对象
            string path = "components.txt";
            FileStream FFLIE = File.OpenRead(path);
            StreamReader STREAMR = new StreamReader(FFLIE, Encoding.Default);
            FFLIE.Seek(0, SeekOrigin.Begin);
            
            string classname;
            string nsp = "csharp_exp4.";
            //对象放到数组中
            ArrayList classList = new ArrayList();
            while (STREAMR.Peek() > -1)
            {
                classname = STREAMR.ReadLine();
                object[] ars = { 3, 4 };


                object gelei = assembly.CreateInstance(nsp + classname, true, BindingFlags.Default, null, ars, null, null);
                
                classList.Add(gelei);

                Type fanshelei = gelei.GetType();
                if (gelei != null)
                    Console.WriteLine("<{0}>类名:{1}", classList.Count, fanshelei.Name);
                //列出每个类的字段、方法;
                MethodInfo[] methodnum = fanshelei.GetMethods();
                Console.WriteLine("  {0}的方法个数:{1}", fanshelei.FullName, methodnum.Length);
                for (int j = 0; j < methodnum.Length; j++)
                {
                    Console.WriteLine("  ({0}){1}", j + 1, methodnum[j].Name);
                }
                    

                FieldInfo[] ziduannum = fanshelei.GetFields();
                Console.WriteLine("  {0}的字段个数:{1}", fanshelei.FullName, ziduannum.Length);
                for (int k = 0; k < ziduannum.Length; k++)
                {
                    Console.WriteLine("  ({0}){1}", k + 1, ziduannum[k].Name);
                }
                    

            }

            Console.Write("\n************1系统操作,2选择操作:*********");
            string kase = Console.ReadLine();
            switch (kase)
            {
                case "1":
                    TimeSpan ttime = new DateTime() - new DateTime(1970, 1, 1);
                    float hm = ttime.Milliseconds;
                    Random myrandom = new Random();
                    int classNum = myrandom.Next(0, 3);
                    object myobject = classList[classNum];//随机选择一个类


                    int numfangfa;
                    while (true)
                    {
                        numfangfa = myrandom.Next(1, 6);
                        if (numfangfa != 4)
                            break;
                    }
                    Type leixing = classList[classNum].GetType();
                    MethodInfo[] methoddn = leixing.GetMethods();
                    Console.WriteLine(leixing.Name + "——" + methoddn[numfangfa - 1].Name + ":" + methoddn[numfangfa - 1].Invoke(myobject, null) + "\n***********************");
                    break;



                case "2":
                    while (true)
                    {
                        //让用户选择,使得用户可以调用所需要的方法(操作)
                        Console.Write("请选择类对象<1-4>或退出0:");
                        int leiduixiang = int.Parse(Console.ReadLine());

                        if (leiduixiang == 0)
                            break;
                        if (leiduixiang < 0 || leiduixiang > 4)
                        {
                            Console.WriteLine("输入错误!\n***********************");
                            continue;
                        }
                        Type curtype = classList[leiduixiang - 1].GetType();
                        MethodInfo[] methodnumss = curtype.GetMethods();
                        Console.WriteLine("  {0}的方法个数:{1}", curtype.FullName, methodnumss.Length);
                        for (int i = 0; i < methodnumss.Length; i++)
                            Console.WriteLine("  ({0}){1}", i + 1, methodnumss[i].Name);
                        Console.Write("请选择方法(except 4):");
                        int nowfangfa = int.Parse(Console.ReadLine());
                        object myshape = classList[leiduixiang - 1];
                        if (nowfangfa < 1 || nowfangfa > 6 || nowfangfa == 4)
                            Console.WriteLine("输入错误!\n***********************");
                        else
                            Console.WriteLine(myshape.GetType().Name + "——" + methodnumss[nowfangfa - 1].Name + ":" + methodnumss[nowfangfa - 1].Invoke(myshape, null) + "\n***********************" +
                                "");
                    }
                    break;
            }

            Console.ReadKey();
        }
    }
}

总结

即使是未知的类,也可以有一把照妖镜.

参考资料:

https://www.pianshen.com/article/2920254015/

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值