C# 反射
实验四:C#反射
具体要求
构建一个components.txt文件,每行代表一个类(比如形状类Shape)的名字(这些类可以来自系统库,或者自己构造);程序逐行扫描该文件,构建对应的类的对象。要求:
-
并把这些对象放到数组中;
-
列出每个类的字段、方法;
-
让用户选择,使得用户可以调用所需要的方法(操作)
-
系统随机选择对象(比如形状),随机的执行其操作。从而看系统演化。可能的话,进行界面展示
环境
- 操作系统: Windows 10 X64
- IDE: visual studio 2017
- 语言:C#
步骤一 :Graphic.cs——>Graphic.dll
1.新建一个项目,通过“项目|添加类”命令向其中添加一个Graphic.cs文件,文件包括图形类的声明和定义。文件内容如下。
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);
}
}
}
2.命令行编译命令(重要)
目的:生成Graphic.dll文件
依次执行以下命令
- path C:\Windows\Microsoft.NET\Framework\v2.0.50727
- cd C:\Users\lenovo\source\repos\csharp实验四\csharp实验四
- csc/target:library Graphic.cs
解释:
- 采用命令行方式对C#文件进行编译的程序是csc.exe
- 为了能执行csc程序,通过path设置路径,命令格式为“ path + csc.exe的文件夹目录 ” ,一般情况下,其位置是 C:\Windows\Microsoft.NET\Framework\v2.0.50727
- cd C:\Users\lenovo\source\repos\csharp实验四\csharp实验四 – 进入存放项目的文件夹
- csc/target:library Graphic.cs – 执行CSC程序
结果:
在C:\Users\lenovo\source\repos\csharp实验四\csharp实验四路径的文件夹下找到Graphic.dll文件
把Graphic.dll文件 移动到csharp实验四\csharp实验四\bin\Debug目录下。ok了
步骤二 :反射查看成员信息、调用未知类方法(System.Reflection 反射命名空间)
知识点1—Assembly类
加载程序集
Assembly assembly = Assembly.LoadFrom("Graphic.dll");//加载程序集(cs文件生成.dll文件,.dll文件是一个程序集)
Console.WriteLine("name of assembley:"+assembly.GetName());//输出程序集的Name
根据类名创建类型的一个实例
object myobj =assembly.CreateInstance(nsp+classname,true, BindingFlags.Default, null, ars, null, null);
知识点2—Type类(获得实例对象的成员信息)
Type mytype = myobj.GetType();
if (myobj!=null)
Console.WriteLine("<{0}>类名:{1}",classList.Count,mytype.Name);
MethodInfo[] ms = mytype.GetMethods();
Console.WriteLine(" {0}的方法个数:{1}", mytype.FullName, ms.Length);
for (int i=0;i<ms.Length;i++)
Console.WriteLine(" ({0}){1}", i+1,ms[i].Name);
FieldInfo[] fs = mytype.GetFields();
Console.WriteLine(" {0}的字段个数:{1}", mytype.FullName, fs.Length);
for (int i = 0; i < fs.Length; i++)
Console.WriteLine(" ({0}){1}", i+1, fs[i].Name);
知识点3—调用方法
[方法名].Invoke([实例对象], [实参])
知识点4—读取文件
//读取文件
string path = "exp5_sharp.txt";
FileStream f = File.OpenRead(path);
StreamReader sr = new StreamReader(f, Encoding.Default);
f.Seek(0, SeekOrigin.Begin);
while (sr.Peek() > -1)//当文件指针。。
{
classname = sr.ReadLine();//类名
...
}
具体代码
static void Main(string[] args)
{
Assembly assembly = Assembly.LoadFrom("Graphic.dll");//加载程序集(cs文件生成.dll文件,.dll文件是一个程序集)
Console.WriteLine("name of assembley:"+assembly.GetName());//输出程序集的Name
Type[] types = assembly.GetTypes();
//读取文件
string path = "exp5_sharp.txt";
FileStream f = File.OpenRead(path);
StreamReader sr = new StreamReader(f, Encoding.Default);
f.Seek(0, SeekOrigin.Begin);
//对象放到数组中;列出每个类的字段、方法;
string classname;
string nsp = "csharp_exp4.";
ArrayList classList = new ArrayList();
while (sr.Peek() > -1)//当文件指针。。
{
classname = sr.ReadLine();//类名
object[] ars = { 3,4};//参数
object myobj =assembly.CreateInstance(nsp+classname,true, BindingFlags.Default, null, ars, null, null);
//加入数组
classList.Add(myobj);
Type mytype = myobj.GetType();
if (myobj!=null)
Console.WriteLine("<{0}>类名:{1}",classList.Count,mytype.Name);
MethodInfo[] ms = mytype.GetMethods();
Console.WriteLine(" {0}的方法个数:{1}", mytype.FullName, ms.Length);
for (int i=0;i<ms.Length;i++)
Console.WriteLine(" ({0}){1}", i+1,ms[i].Name);
FieldInfo[] fs = mytype.GetFields();
Console.WriteLine(" {0}的字段个数:{1}", mytype.FullName, fs.Length);
for (int i = 0; i < fs.Length; i++)
Console.WriteLine(" ({0}){1}", i+1, fs[i].Name);
}
Console.Write("-----------------------\n1系统操作,2选择操作:");
string kase = Console.ReadLine();
switch (kase)
{
case "1":
TimeSpan ts =new DateTime() - new DateTime(1970, 1, 1);
float hm = ts.Milliseconds;
Random myrandom = new Random();
int classNum = myrandom.Next(0, 3);
object myobject = classList[classNum];//随机选择一个类
int funNum;
while (true)
{
funNum = myrandom.Next(1, 6);
if (funNum != 4)
break;
}
Type type = classList[classNum].GetType();
MethodInfo[] md = type.GetMethods();
Console.WriteLine( type.Name+"——" +md[funNum - 1].Name+":" + md[funNum - 1].Invoke(myobject, null)+ "\n-----------------------");
break;
case "2":
while (true)
{
//3)让用户选择,使得用户可以调用所需要的方法(操作)
Console.Write("请选择类对象<1-4>或退出0:");
int cur_class = int.Parse(Console.ReadLine());
if (cur_class == 0)
break;
if(cur_class<0||cur_class>4)
{
Console.WriteLine("输入错误!\n-----------------------");
continue;
}
Type curtype = classList[cur_class - 1].GetType();
MethodInfo[] mds = curtype.GetMethods();
Console.WriteLine(" {0}的方法个数:{1}", curtype.FullName, mds.Length);
for (int i = 0; i < mds.Length; i++)
Console.WriteLine(" ({0}){1}", i + 1, mds[i].Name);
Console.Write("请选择方法(except 4):");
int cur_fun = int.Parse(Console.ReadLine());
object myshape = classList[cur_class - 1];
if (cur_fun < 1 || cur_fun > 6||cur_fun==4)
Console.WriteLine("输入错误!\n-----------------------");
else
Console.WriteLine(myshape.GetType().Name + "——" + mds[cur_fun - 1].Name + ":" + mds[cur_fun - 1].Invoke(myshape, null)+ "\n-----------------------" +
"");
}
break;
}
Console.ReadKey();
}
截图展示
1.类的信息
2.用户选择,调用需要的方法
3.系统随机选择对象(比如形状),随机的执行其操作。