【C#反射】動態創建類型實例


轉載自:https://www.cnblogs.com/dytes/archive/2012/06/29/2569488.html

.NET中除了構造函數外,還有多種方式可以創建類型的實例。下面總結了幾種常見的通過反射創建類型實例的方法。

假設我們需要創建有這樣一個類型的實例:

復制代碼
public class Employee { public String Name { get; set; } public Employee(String name) { Name = name; } public Employee () { } public void Say(String greeting) { Console.WriteLine(String.Format("Employee {0} say: {1} ", Name, greeting)); } }
復制代碼

 

System.Activator

System.Activator類中提供了三組靜態方法來創建類型的實例,每組方法均提供多個重載,適用不同的場景。個別重載方法返回ObjectHandle對象,需要unwrap后才能獲取對象實例。

CreateInstance

CreateInstanceFrom

CreateComInstanceFrom

以下實例代碼演示了如何使用上述方法創建對象實例:

復制代碼
// 使用無參構造函數 var employee = (Employee)Activator.CreateInstance(typeof(Employee)); employee = Activator.CreateInstance<Employee>(); employee.Say("CreateInstance with default ctor"); // 使用有參構造函數 employee=(Employee)Activator.CreateInstance(typeof(Employee), new object[] { "David" }); employee.Say("CreateInstance with ctor with args"); string assembly ="Test, Version=1.0.4562.31232, Culture=neutral, PublicKeyToken=null"; string type="Test.Tests.Employee"; var employeeHandle = Activator.CreateInstance( assembly, type); employee = (Employee)employeeHandle.Unwrap(); employee.Say("CreateInstance and unwrap."); string assemblyPath=@"E:\StudyProj\ShartDev\Test\Test\bin\Debug\Test.exe"; employeeHandle = Activator.CreateInstanceFrom( assemblyPath, type); employee = (Employee)employeeHandle.Unwrap(); employee.Say("CreateInstanceFrom and unwrap.");
復制代碼

 

System.AppDomain

與Activator類似,AppDomain提供了4組實例方法創建類型的實例。除了創建對象外,還指定了對象所歸屬的AppDomain。

CreateInstance

CreateInstanceAndUnwrap

CreateInstanceFrom

CreateInstanceFromAndUnwrap

 

System.Type

使用Type.InvokerMember可以調用類型的方法、屬性。自然也可以通過調用類型的構造函數來創建一個類型的實例。

 

復制代碼
//直接調用無參構造函數 Object obj = typeof(Employee).InvokeMember(null, BindingFlags.CreateInstance, null, null, null); Employee employee =obj as Employee; employee.Say("InvokeMember default ctor"); // 使用帶參數的構造函數 obj = typeof(Employee).InvokeMember(null, BindingFlags.CreateInstance, null, null, new object[] { "david" }); employee = obj as Employee; ((Employee)obj).Say("InvokeMember ctor with argument");
復制代碼

 

 

System.Reflection.ConstructorInfo

除了直接適用InvokerMember調用構造函數外,還可以先以反射的方式獲取構造函數對應的MemberInfo,具體類型為ConstructorInfo,然后使用其Invoke方法。

// 首先獲取構造函數,然后再Invoke ConstructorInfo ctor = typeof(Employee).GetConstructor(new Type[] { typeof(string) }); var emp = (Employee)ctor.Invoke(new object[]{"david"}); emp.Say("ConstructorInfo");

本來一步可以完成的操作,分兩邊走完的確是麻煩了些,但好處在於獲取ConstructorInfo之后,后續多次調用Invoke時,避免重復綁定,可以提高效率,適用於需要重復多次使用同一個構造函數創建實例的場景。反射的綁定過程是按照字符串比較的方式在程序集元數據中查找匹配的成員,速度較慢。

創建實例:4種方式創建類型實例

 Type school = typeof(School);
            //需要添加對Education.dll的引用才能正確執行
            // Activator創建實例
            School schoolActivator = (School)Activator.CreateInstance(school);
            schoolActivator.Name = "schoolActivator";

            // 構造函數 創建實例
            ConstructorInfo Conmethod = school.GetConstructor(new[] { typeof(string)} );
            var schoolType= (School) Conmethod.Invoke(new[] { "南平小學"});
            schoolType.Name = "schoolType";

            //Assembly創建實例
            School schoolAssembly = (School)school.Assembly.CreateInstance("Education.School");
            schoolAssembly.Name = "schoolAssembly";
        
         //InvokeMember 創建實例
        // Name 第一個參數是 是成員類型名字,構造函數是與類同名,所以只要填null。
        //BindingFlags 篩選類型
        //Binder type實例
       //Object?[]?agrs  傳入函數的參數,這個函數在對象實例上調用,所以要傳入實參new Object[] { 2 }
       Object[] args = new Object[] { 8 }; 如果沒有參數那么就填null
       Object obj =t.InvokeMember(null,BindingFlags.CreateInstance, null, null, args);

 

 

字段操作 :獲取類型字段成員信息,並且給實例字段賦值或者獲取實例字段的值

   //獲取私有 字段 並且賦值思路:獲取School類型信息然后生成實例類school,獲取私有字段name信息,然后用這個信息對實例類就行 賦值。
            Type schoolTypeInfo = typeof(School);
            FieldInfo field = schoolTypeInfo.GetField("name", BindingFlags.Instance | BindingFlags.NonPublic);


            //發現一個小秘密,獲取的FieldInfo 是一把萬能的鑰匙,可以對所有的實例成員進行操作。
            School school = (School)Activator.CreateInstance(schoolTypeInfo);
            School ssse = new School("dfsdfd");
            field.SetValue(school, "sed");//傳入實例,field事時保存類型信息
            field.SetValue(ssse, "sed");
            Console.WriteLine(field.GetValue(school));//獲取實例字段的值,因為field保存字段信息,可以對實例字段直接進行操作
            Console.WriteLine(school.Name);
            Console.WriteLine(ssse.Name);

 

屬性操作 

   //   ==================:獲取類型字段成員信息,並且給實例字段賦值或者獲取實例字段的值

            //獲取私有 字段 並且賦值思路:獲取School類型信息然后生成實例類school,獲取私有字段name信息,然后用這個信息對實例類就行 賦值。
            Type schoolTypeInfo = typeof(School);
          PropertyInfo field = schoolTypeInfo.GetProperty("Name", BindingFlags.Instance | BindingFlags.Public);


            //發現一個小秘密,獲取的FieldInfo 是一把萬能的鑰匙,可以對所有的實例成員進行操作。
            School school = (School)Activator.CreateInstance(schoolTypeInfo);
            School ssse = new School("dfsdfd");
            field.SetValue(school, "sed");//傳入實例,field事時保存類型信息
            field.SetValue(ssse, "sed");
            Console.WriteLine(field.GetValue(school));//獲取實例字段的值,field保存字段信息。
            Console.WriteLine(school.Name);
            Console.WriteLine(ssse.Name);

         //=====================================================================================

 

 

 

數組,委托和泛型類型的創建

Array

Array類型可以使用靜態方法Array.CreateInstance方法創建。Array類還提供了其他重載方法來創建多維數組。

var array = Array.CreateInstance(typeof(int),20);
Console.WriteLine(array.GetType().Name+" " +array.Length);

//賦值
arr.SetValue("hello", 0);
arr.SetValue("world", 1);

//取值
arr.GetValue(0);

//將其轉換為靜態數組
string[] cs_arr = (string[])arr;

 

委托

 用Delegate.CreateDelegate創建委托

MethodInfo methodInfo = typeof(CreateInstanceTest).GetMethod("StaticDoSomething",BindingFlags.Public|BindingFlags.Static); Delegate dele = Delegate.CreateDelegate(typeof(DoSomethingDelegate),methodInfo); dele.DynamicInvoke("just say hi");

methodInfo.CreateDelegate 創建委托 源代碼

 
            Assembly assem = typeof(Program).Assembly;
            Type tExForm = assem.GetType("EventTest.Evenform");
            Form obExform = (Form)Activator.CreateInstance(tExForm);
            EventInfo evClick = tExForm.GetEvent(nameof(obExform.Click));
            Type tDelegate = evClick.EventHandlerType;

            MethodInfo miHandler = typeof(Program).GetMethod("LuckyHandler", BindingFlags.NonPublic | BindingFlags.Instance);

            //第一種方法 把委托 綁定到this對象的 miHandler方法上 然后返回委托指針。
            Delegate delage1 = Delegate.CreateDelegate(tDelegate, this, miHandler);
            delage1.DynamicInvoke(new object(), new EventArgs());

            //第二種方法把方法 綁定到指定對象的委托上
            Delegate delageMeth2=  miHandler.CreateDelegate(tDelegate, this);
            delageMeth2.DynamicInvoke(new object(), new EventArgs());

            //第三種方法、用表達式樹根據方法的簽名創建DelegateType,然后 Methodinfo.CreateDelegate 委托
            Delegate delageMeth3 = miHandler.CreateDelegate(Expression.GetDelegateType(
            (from parameter in miHandler.GetParameters() select parameter.ParameterType)
            .Concat(new[] { miHandler.ReturnType })
            .ToArray()),this);
            delageMeth3.DynamicInvoke(new object(), new EventArgs());

Generic

創建泛型類型的實例,首先要獲取對應的開放類型(Open type)的引用,然后調用Type類型的MakeGenericType方法,傳入一個包含泛型參數的數組即可獲取一個封閉類型(Closed Type).使用該封閉類型,調用Activator接受Type參數的某個方法既可以構造出具體的實例。

 

Type open = typeof(Dictionary<,>); Type closeType = open.MakeGenericType(typeof(String),typeof(object)); object obj = Activator.CreateInstance(closeType); Console.WriteLine(obj.GetType());

 

 

以上即是常用的幾種創建對象實例的方式,實際應用中可以根據具體場景做選擇。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM