<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      記錄點滴收獲,匯聚知識樂園

      腳步無法到達的地方,目光可以到達;目光無法到達的地方,夢想可以到達

      導航

      反射(原創推薦)

       在程序中,當我們需要動態的去加載程序集的時候(將對程序集的引用由編譯時推移到運行時),反射是一種很好的選擇。反射為.NET類型提供了高度的動態能力,包括:元數據的動態查詢、綁定與執行、動態代碼生成。常用的反射類型包含在System.Reflection和System.Reflection.Emit,反射包括程序集反射、類型反射、接口反射、類型成員反射。

      編譯時加載程序集

      下面先從一個簡單的例子說起,假如我們有一個Point類如下所示:

      using System;
      public class Point
      {
      public int x;
      public int y;
      public void Print()
      {
      Console.WriteLine("[{0},{1}]",x,y);
      }
      }

      先將其編譯成Point.dll文件,然后我們需要在Reflect.cs文件中用到這個類型:

      代碼如下:

      using System;
      public class Reflect
      {
      public static void Main()
      {
      Point p=new Point();
      p.x=100;
      p.y=200;
      p.Print();
      }
      }

      然后我們編譯這個文件,會發現拋出異常,告訴我們不存在Point類型,也就是說Point是一個未知類型,編譯器根本不知道它,那怎么辦了,這里我們需要在編譯時對Point程序集進行引用,這樣才能讓編譯器知道它,在很多應用程序開發框架中在我們編譯項目的時候框架會自動進行程序集的引用,但是在這里我們的編譯工作是手動進行的,因此我們也需要手動的引用程序集。下面是編譯命令:

      csc /r:Point.dll Reflect.cs

      這樣我們在編譯Reflect.cs文件的過程中就實現了對Point程序集的引用,這樣編譯器就識別了程序集中Point類型信息。其實任何類型信息的使用都需要有程序集的引用,不然的話編譯器會不認識這個類型,編譯就無法通過。我們可能會想,我們在很多時候進行編譯的時候并沒有對哪個程序集進行引用么?不是沒有,而是很多預定義的類型信息編譯器會默認幫我們進行引用,不需要我們顯示的進行引用,比如mscorlib程序集,它是.NET一個核心程序集,里面包含了很多常用的預定義的類型信息,因此C#編譯器在編譯的時候會默認對它進行引用,可能我們會想,我們怎么知道一段代碼在編譯的過程中它到底都引用了哪些程序集了,這里就需要借助于元數據,下面我們通過ildasm工具查看了編譯好的Reflect.exe程序集中的元數據,我們只截取了其中一段進行說明。

      // Metadata version: v4.0.30319
      .assembly extern mscorlib
      {
      .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
      .ver 4:0:0:0
      }
      .assembly extern Point
      {
      .ver 0:0:0:0
      }

      從這段元數據中我們可以看出,這個程序集中包含了對Point程序集和mscorlib程序集的引用。

      利用反射實現延遲加載程序集

      在上面所舉的例子中,所有對程序集的引用都是在編譯時進行的,因此效率會比較高。但是在某些特定的情況下,我們需要對程序集進行延遲加載,即將對程序集的引用由編譯時推移到運行時,反射是一種很好的選擇,在最開始我們講過,反射為.NET類型提供了高度的動態能力,包括:元數據的動態查詢、綁定與執行、動態代碼生成,這些功能的實現都離不開元數據。下面我們看看反射的具體實現。

      using System;
      using System.Reflection;

      class Test
      {
      public static void Main(string[] args)
      {
      string assemblyName=args[0];
      string typeName=args[1];
      string fieldName1=args[2];
      string fieldName2=args[3];
      string methodName=args[4];
      Assembly assembly=Assembly.Load(assemblyName); //手動加載程序集
      Type type=assembly.GetType(typeName); //獲取程序集中的類型

      //查詢
      MemberInfo[] mis=type.GetMembers(); //獲取類型中的成員信息
      for(int i=0;i<mis.Length;i++)
      {
      Console.WriteLine(mis[i]);
      }

      object obj=Activator.CreateInstance(type); //創建對象實例

      //查詢字段
      FieldInfo field1=type.GetField(fieldName1);
      FieldInfo field2=type.GetField(fieldName2);
      field1.SetValue(obj,100); //實例成員必須依附于對象實例才能賦值
      field2.SetValue(obj,200);

      //查詢方法
      MethodInfo method=type.GetMethod(methodName);

      //調用方法
      method.Invoke(obj,null); //實例方法必須依附于對象實例才能執行
      }
      }

      這里我們在編譯這段代碼的時候并沒有對Point程序集進行引用,而是將其推移到了運行時。在這段代碼中Point類型并不存在,因此我們并不能用Point類型來創建對象實例。但是下面的幾個操作是針對于對象的實例成員進行的,他們需要依附于對象的實例,因此我們在這里根據在運行時加載進來的類型信息創建了一個對象,但是編譯時類型信息是未知的。我們可以通過查看它的元數據得知它編譯后并沒有對Point程序集進行加載。

      那么運行時怎么對程序集進行加載了,這里我們就需要將需要加載的程序集的信息在入口點函數中以參數的形式傳遞進來,下面是運行時的命令:

      在這段命令中我們指出了運行時需要加載的程序集的名稱和其中的類型的名稱以及類型中的成員信息。由于類型信息在編譯時是未知的,因此我們并不清楚在運行時會加載進來什么樣的類型信息(需要通過傳入的參數確定)。也就是說我們現在所進行的一些操作是針對一個不確定的類型的(如果我們事先并不了解Point的類型信息)。而在上面的代碼中我們之所以能夠對加載進來類型信息進行這樣的處理,是因為我們事先已經對Point類型信息有所了解了,因此我們遵循了這樣一個隱式的約定來對類型進行操作。但是在很多情況下我們是并不了解未來加載進來的類型信息它所遵循的約定。因此在運行時,反射需要做很多的校驗工作,也就是說把本來應該在編譯時做的校驗工作都推移到了運行時,比如參數類型的兼容性以及所調用的方法是實例方法還是靜態方法,因此反射的效率比較低。

      利用接口提高反射效率

       那么怎么樣才能提高反射的效率了,很簡單,我們需要明確約定,也就是說只有滿足了約定信息的類型才能被加載進來,也因此我們對類型成員的處理必須是滿足了這一約定的,這樣雙方都有了一個共同的約定。那么我們用什么來實現這一約定了,當然需要用到接口了。
         我們對上面的例子進行改進,通過對Point類型的觀察,我們可以得到這樣一個接口,我們先看接口的實現,并將其編譯為IPoint.dll文件。

      using System;
      public interface IPoint
      {
      public int X{set;get;}
      public int Y{set;get;}

      void Print();
      }

      下面我們來實現Point類,并對其進行編譯,注意:在編譯時確保對IPoint.dll的引用。

      using System;
      public class Point :IPoint
      {
      private int x;
      private int y;

      public int X
      {
      set{this.x=value;}
      get{return x;}
      }

      public int Y
      {
      set{this.y=value;}
      get{return y;}
      }

      public void Print()
      {
      Console.WriteLine("[{0},{1}]",this.X,this.Y);
      }
      }

      下面我們再來看Reflect類的實現,在對其進行編譯時同樣需要對IPoint.dll進行引用。

      using System;
      using System.Reflection;

      class Test
      {
      public static void Main(string[] args)
      {
      string assemblyName=args[0];
      string typeName=args[1];

      Assembly assembly=Assembly.Load(assemblyName); //手動加載程序集
      Type type=assembly.GetType(typeName); //獲取程序集中的類型

      IPoint obj=(IPoint)Activator.CreateInstance(type); //通過接口創建對象實例
      obj.X=100;
      obj.Y=200;
      obj.Print();
      }
      }

      最后運行編譯后的Reflect.exe文件,運行時同樣需要傳入程序集信息和類型信息。這里我們看到Point程序集和Reflect程序集在編譯時都對IPoint程序集進行了引用,因此在Reflect程序集中,雖然在編譯時并沒有Point類型信息,但是有IPoint接口信息,因此我們通過這個接口很方便的實現了我們需要的操作,只要未來加載進來了類型是實現了IPoint接口的就可以了,這樣在運行時就不需要進行大量的校驗工作了,這些工作都還原到了編譯時,因此使用接口來實現反射也大大提高了反射的性能。

      聲明:本人接觸.NET時間不長,希望各位路過的高手要是覺得文中有錯誤的話能及時告訴我,本人力求最做到所有信息的正確性,謝謝。







      posted on 2011-12-18 00:53  guowenhui  閱讀(6749)  評論(21)    收藏  舉報

      主站蜘蛛池模板: 精品午夜福利在线视在亚洲| 中文字幕不卡在线播放| 东港市| 亚洲日韩精品一区二区三区无码 | 国产午夜亚洲精品国产成人| 夜夜躁狠狠躁日日躁| 日韩精品亚洲专在线电影| 欧美大香线蕉线伊人久久| 国产99久久无码精品| 亚洲另类激情专区小说图片| 国产精品欧美福利久久| 边吃奶边添下面好爽| 中文字幕结果国产精品| 成人国产永久福利看片| 亚洲天堂精品一区二区| 手机看片日本在线观看视频| 午夜亚洲www湿好爽| 国产中年熟女高潮大集合| 四虎影视一区二区精品| 成在线人免费视频| 成人福利国产午夜AV免费不卡在线 | 一本色道婷婷久久欧美| 亚洲综合精品第一页| 国产一区二区在线影院| 亚洲精品香蕉一区二区| 深夜视频国产在线观看| 无套后入极品美女少妇| 久久中文字幕国产精品| 丁香五月婷激情综合第九色| 久久香蕉欧美精品| 国产成人精品2021欧美日韩| 亚洲精品日韩在线观看| 亚洲中文字幕无码av永久| 久久天天躁狠狠躁夜夜婷| 少妇人妻偷人一区二区| 国产不卡一区二区精品| 深夜福利成人免费在线观看| 中文字幕乱妇无码AV在线| 国产精品日韩中文字幕熟女| 午夜三级成人在线观看| 少妇xxxxx性开放|