反射,插件示例

反射:

反射的概念是由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类库,添加后就能编译成功。

 

posted @ 2018-09-08 08:17  琴鸟  阅读(481)  评论(1编辑  收藏  举报