反射:
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改其本身状态或行为的一种能力。
不需要走过去看前面是否有阻挡物,只需要利用声波的反射,就可以知道前面是否有阻挡,和阻挡物有多远。
在程序中也是如此,现实中利用声波,导致我们可以不用实际走过去,而程序中利用 类的自我描述信息。导致我们不需要一个实际的对象,只要告诉我类的命名空间和类名,或者java的包名和类名。就可以知道类的方法属性,甚至建立一个实例出来,或修改类属性。
一定要清晰认识到,由于提出了程序应该有访问,检测,修改自己状态和行为的能力的概念,所以才有了反射技术的概念。所以反射一般必须满足它设计的2个初衷,1.自我描述,2自我修改。
c#的定义
反射:一个运行的程序查看本身的元数据或其他程序的元数据的行为。
java反射的一般定义
JAVA反射机制是在运行状态中,
1.对于任意一个类,都能够知道这个类的所有属性和方法;
2.对于任意一个对象,都能够调用它的任意方法和属性;
这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制
它是现代框架的灵魂,几尽所有的框架能够提供的一些自动化机制都是靠反射实现的,这也是为什么基础框架都不允许你覆盖掉默认的无参构造器的原因,因为框架需要以反射机制利用无参构造器创建实例。
c# 的插件例子:
子游戏 ,编译为 一个 一个 的 dll. 而 游戏 管理 中心 。就是界面 程序 。可以 加载 任何游戏 插件 ,只要 实现 了 子游戏 接口。
原来 看 c++ 写的 比较 复杂 。在c#中 真的是 非常 简便了 。超级简单。
游戏管理中心 。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Reflection; namespace helloworld { public interface Game_Interface { string GameName(); void Start(); void End(); } public class GameCenter { List<Game_Interface> Games; public GameCenter() { Games = new List<Game_Interface>(); } public void StartGames() { //模拟从xml配置文档,读出了游戏名字。 //string game1name = getnameFormxml(); List<string> gamenames=new List<string>(); gamenames.Add("Game_land"); gamenames.Add("Game_machong"); foreach(string gamename in gamenames) { Assembly tempAss = Assembly.Load(gamename);//根据程序集名字装载程序集.xxx.dll Type temptype = null; // object obj = CreateInstance1(tempAss, "subgame." + gamename, out temptype);//一般2种方法得到一个类的实例和类型信息. 1通过指定命名空间加类名 xxx.xxx object obj = CreateInstance2(tempAss, typeof(Game_Interface),out temptype);//2.通过查看某些属性。如这里是查看是否有实现了某个接口的类。 MethodInfo m1 = temptype.GetMethod("Start");//调用方法可以有2种方式 1.继续反射。从对象中。手工调用某个方法。 m1.Invoke(obj, null); Game_Interface tempGame = obj as Game_Interface;//2.如果是实现了某个接口.那么可以转为接口类型.一般采用这种,强类型肯定比手工写方法名字 更安全。 if(tempGame!=null) { tempGame.Start(); } } } object CreateInstance1(Assembly tempAss, string typename,out Type mytype) { Type temptype = tempAss.GetType(typename);//"subgame." + gamename object obj = Activator.CreateInstance(temptype);//从程序集中,根据命名空间和类名组成的全地址,实力化一个对象出来。 mytype = temptype; return obj; } object CreateInstance2(Assembly tempAss, Type interfacetype, out Type mytype) { Type[] alltypes = tempAss.GetTypes(); Type wantType = null; for (int i = 0; i < alltypes.Length;i++ ) { Type itype= alltypes[i].GetInterface("Game_Interface");//看看有没有接口类型。返回的只是接口类型而已。 if (itype != null) { wantType = alltypes[i];//这个才是实现了接口的类型。 break; } } if (wantType != null) { object obj = Activator.CreateInstance(wantType); mytype = wantType; return obj; } else { mytype = null; return null; } } public void StopGame(int gameIndex) { } public void CreatRound(int gameIndex) { } } }
子 游戏
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace subgame { public class Game_machong:helloworld.Game_Interface { public string gamename = "machong"; public string GameName() { return gamename; } public void Start() { Console.WriteLine("Start machong"); } public void End() { Console.WriteLine("End machong"); } } }
子游戏
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace subgame { public class Game_land:helloworld.Game_Interface { public string gamename = "land"; public string GameName() { return gamename; } public void Start() { Console.WriteLine("Start land"); } public void End() { Console.WriteLine("End land"); } } }
java 的例子
//反射:测试运行时创建类,修改私有变量为外部可以访问。 //一定要清晰,由于提出了程序应该有访问,检测,修改自己状态和行为的能力的概念,所以才有了反射技术的概念。 //所以反射一般必须满足它设计的2个初衷,1.自我描述,2自我修改。 private void Myreflect() { MyBook cpp=new MyBook(4, 1, "c++"); LSLog.Log_INFO(cpp.getInfo()); try { //1.running time create obj 这就是反射的初衷1:自我描述,不需要编译时,运行时都可以建立一个对象,所以为插件机制提供了简便的方式。 Class BookReflect= Class.forName("com.linson.android.hiandroid2.JavaPractice.MyBook"); MyBook javabook= (MyBook) BookReflect.getConstructor().newInstance(); //2.set value to private field. 这就是反射的初衷2:自我修改,可以把私有字段设置为可以访问。为某些特殊情况提供了可能。当然也是双刃剑,可以自我修改,就违背了当初类设计的初衷。 Field privateField=BookReflect.getDeclaredField("price"); privateField.setAccessible(true);//这里的自我修改,满足了反射必须有自我修改的能力的规范。 privateField.set(javabook, 8); Field fname=BookReflect.getField("name"); fname.set(javabook, "java"); LSLog.Log_INFO(javabook.getInfo()); } catch (Exception e) { LSLog.Log_Exception(e); }
c# 例子
“反射”其实就是利用程序集的元数据信息。 反射可以有很多方法,编写程序时请先导入 System.Reflection 命名空间。 1、假设你要反射一个 DLL 中的类,并且没有引用它(即未知的类型): Assembly assembly = Assembly.LoadFile("程序集路径,不能是相对路径"); // 加载程序集(EXE 或 DLL) dynamic obj = assembly.CreateInstance("类的完全限定名(即包括命名空间)"); // 创建类的实例 2、若要反射当前项目中的类(即当前项目已经引用它了)可以为: Assembly assembly = Assembly.GetExecutingAssembly(); // 获取当前程序集 dynamic obj = assembly.CreateInstance("类的完全限定名(即包括命名空间)"); // 创建类的实例,返回为 object 类型,需要强制类型转换 3、也可以为: Type type = Type.GetType("类的完全限定名"); dynamic obj = type.Assembly.CreateInstance(type); 4、不同程序集的话,则要装载调用,代码如下: System.Reflection.Assembly.Load("程序集名称(不含文件后缀名)").CreateInstance("命名空间.类名", false); 如: dynamic o = System.Reflection.Assembly.Load("MyDll").CreateInstance("MyNameSpace.A", false); 5、根据对象实例创建该对象所属类的新对象 Type type = protocol.GetType(); //获取protocol类型 Assembly assembly = Assembly.GetExecutingAssembly(); // 获取当前程序集 string name = type.FullName; IProtocol obj = (IProtocol)assembly.CreateInstance(name); //根据类名获得新对象 注意:由于要用到dynamic ,需要把target 改为4.0 ,如果编译时出现“找不到编译动态表达式所需的一个或多个类型。是否缺少引用?”的错误,是因为缺少一个引用,在项目里引用Miscorsoft.CSharp类库,添加后就能编译成功。