程式集載入與反射(一):理論篇

K戰神發表於2015-06-23

目錄

  • 程式集載入
  • 獲取型別資訊
  • 構造型別例項
  • 通過反射發現成員
  • 呼叫成員

 

一、程式集載入

Load方法:CLR通過呼叫System.Rreflection.Assemblly類的靜態方法來顯示載入程式集。

public static Assembly Load(AssemblyName assemblyRef);
public static Assembly Load(string assemblyString);


LoadFrom方法:同樣我們可以使用 遠端載入程式集。此方法首先開啟程式集,並通過 public static AssemblyName GetAssemblyName(string assemblyFile);方法提取到程式集名稱,然後再會使用Load方法載入程式集。

public static Assembly LoadFrom(string path);

ReflectionOnlyLoad方法:載入程式集,只是獲取程式集的相關資訊。但CLR禁止此程式集中的程式碼執行。

public static Assembly ReflectionOnlyLoad(string assemblyString);

同樣也有ReflectionOnlyLoadFrom

public static Assembly ReflectionOnlyLoadFrom(string path);

 

二、獲取型別資訊

1、System.Type.GetType方法

public static Type GetType(string typeName);

字串必須執行的是全名,對於基元型別不能識別,識別CLR型別。

2、System.Type.ReflectionOnlyGetType

public static Type ReflectionOnlyGetType(string typeName, bool throwIfNotFound, bool ignoreCase);

只是顯示反射上下文內容,不能夠執行程式碼。

3、操作符typeof(),可以對型別進行晚期繫結並與早期繫結型別進行比對。

static Encryption(object o)
        {
             //早期繫結:o.GetTye()  
             //晚期繫結typeof
            if (o.GetType() == typeof(Encryption))
            {
            }
        }   

 

三、構造型別例項

1、System.Activator.CreateInstance

public static object CreateInstance(Type type);
public static ObjectHandle CreateInstance(string assemblyName, string typeName);

 上面的方法返回值有的是ObjectHandle型別,此型別允許將一個AppDomian中的物件傳送到另一個AppDomian而且不需要具體化哪個物件。如果需要具體化具體的型別就可以呼叫 Unwrap()方法。

 2、System.Activator.CreateComInstanceFrom

public static ObjectHandle CreateComInstanceFrom(string assemblyName, string typeName);

程式集和型別都是字串直接指定,不過,程式集需要使用LoadFrom方法來載入得到程式集,並且提取名稱作為引數傳遞。當然對於返回值我們也需要呼叫Unwrap()進行具體化。

System.Reflection.Assembly assy= System.Reflection.Assembly.LoadFrom("");

System.Activator.CreateComInstanceFrom(assy.FullName, "Encryption");

 

四、通過反射發現成員

 層次結構

 因為Reflection.MemberInfo是成員結構層次的根,所以需要了解一下MemberInfo的成員組成:

 1、執行以下程式碼,區分一下DeclaringType和ReflectedType:

DeclaringType:宣告方法的類;ReflectedType:當前的反射類

 public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            System.Reflection.MemberInfo[] mi = typeof(MyType).GetMembers();            

            foreach (var m in mi)
            {
               var dt=  m.DeclaringType;

               var rt = m.ReflectedType;
            }
        }
    }
    public sealed class MyType
    {

        public override string ToString()
        {
            return null;
        }
    }

ToSting()方法,因為宣告它的類和當前所在的反射類是同一個即MyType。

Equal()方法,因為宣告它的類是Object,但是當前反射類是MyType。

以上就是DeclaringType和ReflectedType的區別。

 

2、BindingFlags:篩選返回的成員種類

我們可以呼叫Type的 GetMethod、GetProperty、GetNestedType各種Get。我們可以組合BindingFlags,來篩選我們需要的東西。

 

五、呼叫成員的型別

我們可以找出我們需要的東東,然後我們可以進行呼叫。呼叫屬性、方法、建構函式等等。

呼叫FieldInfo,可以獲取或者設定欄位的值;

呼叫ConstructorInfo,可以向構造傳遞實參,從而構造型別的一個例項;

呼叫MethodInfo,可以通過傳遞實參來呼叫方法,並返回它的返回值;

呼叫PropertyInfo,可以呼叫屬性的get和set訪問其方法。

 1、呼叫方法

public object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, CultureInfo culture);

呼叫此方法可以在成員型別裡搜尋一個匹配的型別成員,如果沒找到,丟擲異常。如果找到,就會呼叫此成員。我們可以歸納以上行為為兩個階段:繫結和呼叫。

我們呼叫一個繫結器方法時,首先我們傳遞 目標成員 name、方法的所有引數型別 args 、指定的 BindingFlags invokeAttr 。

引數 name :目標成員。名字

引數 invokeAttr :這些位標識的組合可以幫助我們更好的定位我們的成員 IgnoreCase = 1, DeclaredOnly = 2,Instance = 4,Static = 8,Public = 16等

引數 binder :它的型別從System.Relflection.Binder 抽象型別派生的,從Binder派生的型別,封裝了InverMember方法確定繫結型別的規則。編譯器為我們定義了System.DefaultBinder 的實際型別可以為我們使用。可以幫助我們自動的型別轉換。

引數 target : 目標成員所在類的例項的一個引用。靜態類 =null。

引數 args: 傳遞的引數。

引數 culture: 如果有自己的繫結器可以使用此引數,如果前面引數使用了System.DefaultBinder,culture引數就可以省略了。

2、一次繫結,多次呼叫

我們利用Type的InvokeMember方法可以,訪問任何成員。但是如果多次呼叫,我們就需要多次進行繫結並呼叫,比較損耗效能。我們可以使用:

 

  

相關文章