在一些高级的开源项目中通常会使用到反射和打特性,如果对于c#初级的程序员第一眼看到肯定一脸懵逼,我以前也是这样过来的所以今天公司没啥事情可以干,就写一下笔记 ,unity 开源项目ET(以前看et项目时只知道原理不知其中的代码所以今天自已实现一下原理) 中就使用了这种方式实现。在此我解析一下反射与自定义特性的主要功能(反射网上搜索一大堆这里主要是介绍自定义特性的与反射结合使用的好处):
反射:反射就是通过加载程序集(什么是程序集,程序集就是一个文件,一个存放了IL语句的dll,它可以是C#所有的语法或者说一个项目中所有的cs文件,打包成IL语言,在此我们不学习IL语法只知道它是什么)获取类(class)再获取类中的属性、方法、字段;
所以下面主要实现的功能是
例子 一: 通过反射调用方法
自定义 一个 类(可以是抽象类也可以是普通类)
//命名空间
namespace ConsoleApp1
{
//一个基类
abstract class Game
{
public virtual void start() { }
public virtual void updata() { }
}
//继承Game
class Compent : Game
{
public override void start() {
Console.WriteLine("my start");
}
public override void updata()
{
Console.WriteLine("updata");
}
}
}
然后在主线程中解析程序集调用方法
namespace ConsoleApp1
{
class Program
{
//存放所有继承Game的子类
private static List<Game> Games = new List<Game>();
//是否退出
private static bool isexit = false;
static void Main(string[] args)
{
//获取程序集所有的类
Type[] types = typeof(Program).Assembly.GetTypes();
//遍历
foreach (Type t in types) {
// AttributeLogic(t);
//如果是Game本身就下一条
if (t.Name == typeof(Game).Name)
continue;
//判断当前类是否继承Game
if ( typeof(Game).IsAssignableFrom(t))
{
//实例一个Game 子类
object reflectTest = Activator.CreateInstance(t);
Game g = reflectTest as Game;
Games.Add(g);
}
}//找到了程序集所有继承Game的子类了并把它们都放在Games列表里边
init();
//结束主线程
while (true)
{
if (Console.ReadKey().Key == ConsoleKey.A)
{
isexit = true;
break;
}
}
}
//开始处理
static void init()
{
foreach (var item in Games)
{
item.start();
}
new Thread(GameLogic).Start();
}
static void GameLogic()
{
while (!isexit)
{
foreach (var g in Games)
{
g.updata();
}
Thread.Sleep(20);
}
}
}
}
运行结果是
my start
updata
updata
简单的反射调用方法已经完成了。
例子二:自定义特性的与反射结合使用
首先我自定义自已的一个特性
namespace ConsoleApp1
{
//自定义特性类
[AttributeUsage(AttributeTargets.All)]
class GameSystem:Attribute//正常格式是GameSystemAttribute这样的
{
public GameSystem() { }
}
//自定义一个player类
class player
{
//GameSystem特性类的名字,如果定义的时候特性类的名字是这样GameSystemAttribute打上特性也是一样的
[GameSystem]//给start打上特性
public void start()
{
Console.WriteLine("GameSystem start");
}
[GameSystem]//也给updata打上特性
public void Updata()
{
Console.WriteLine("my updata");
}
}
}
然后在主线程中测试
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
Type[] types = typeof(Program).Assembly.GetTypes();
foreach (Type t in types) {
AttributeLogic(t);
}
}
static void AttributeLogic(Type type)
{
foreach (MethodInfo method in type.GetMethods())
{
foreach (Attribute attr in method.GetCustomAttributes())
{
if (attr is GameSystem)
{
object reflectTest = Activator.CreateInstance(type);
MethodInfo methodInfo = type.GetMethod(method.Name);
methodInfo.Invoke(reflectTest, null);
}
}
}
}
}
}
运行结果是
GameSystem start
my updata
这就是打特性的神其之处
只要你在任何方法中打上[GameSystem] 只要是无参的都可以任意执行(方法有返回值也可以),你也可以自已拓展方法中的参数。