1. 程式人生 > >十一、C#入門基礎11(委託,事件,反射)

十一、C#入門基礎11(委託,事件,反射)

一、委託

C# 中的委託(Delegate)類似於 C 或 C++ 中函式的指標。
委託(Delegate) 是存有對某個方法的引用的一種引用型別變數。
引用可在執行時被改變。
委託(Delegate)特別用於實現事件和回撥方法。
所有的委託(Delegate)都派生自 System.Delegate 類。

宣告委託
委託宣告決定了可由該委託引用的方法。
委託可指向一個與其具有相同標籤的方法。
delegate

例項化委託
一旦聲明瞭委託型別,委託物件必須使用 new 關鍵字來建立,且與 一個特定的方法有關。
當建立委託時,傳遞到 new 語句的引數就像方法呼叫一樣書寫,但 是不帶有引數。

二、事件

事件(Event) 基本上說是一個使用者操作,如按鍵、點選、滑鼠移動等等,或 者是一些出現,如系統生成的通知。應用程式需要在事件發生時響應事件。例 如,中斷。事件是用於程序間通訊。

事件的概念:
通過事件使用委託
事件在類中宣告且生成,且通過使用同一個類或其他類中的委託與事件處理程式關聯。
包含事件的類用於釋出事件。這被稱為釋出器(publisher) 類。
其他接受該事件的類被稱為訂閱器(subscriber) 類。
事件使用釋出-訂閱(publisher-subscriber) 模型。
釋出器(publisher)是一個包含事件和委託定義的物件。
事件和委託之間的聯絡也定義在這個物件中。
釋出器(publisher)類的物件呼叫這個事件,並通知其他的物件。
訂閱器(subscriber) 是一個接受事件並提供事件處理程式的物件。
在釋出器(publisher)類中的委託呼叫訂閱器(subscriber)類中的方法(事件處理程式)。

宣告事件:
在類的內部宣告事件,首先必須宣告該事件的委託型別。
宣告事件本身,使用 event 關鍵字

實現的程式碼(委託,事件):

Hello類(釋出器):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _11
{
    public class Hello
    {
        /// <summary>
        /// 定義好事件的委託
        /// </summary>
        public delegate void ShowHiDelegate();
        /// <summary>
        /// 定義好一個你好的事件
        /// </summary>
        public event ShowHiDelegate ShowHievent;
        /// <summary>
        /// 執行問好的方法 
        /// </summary>
        public void ClickShowHievent()
        {
            if (ShowHievent!=null)
            {           
                //執行問好的方法   
                ShowHievent();
            }
        }

    }
}

Jp類(訂閱器):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _11
{
    /// <summary>
    /// 日本人
    /// </summary>
    public class Jp
    {
        public void ShowHi()
        {
            Console.WriteLine("日本人說你好");
        }


    }
}

USA類(訂閱器):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _11
{
    public class USA
    {
        public void ShowHi()
        {
            Console.WriteLine("美國人說你好");
        }


    }
}

Program類(實現的類):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _11
{
    class Program
    {
        /// <summary>
        /// 可以將方法作為引數進行傳遞的特殊的引用型別變數
        /// 實現方法的模板->抽象類 介面 (針對於方法)
        /// 實現委託的方法必須和委託定義的是一模一樣  (不能有任何改變 引數的名稱可以不一樣)
        /// </summary>
        //宣告一個委託
        //delegate void ShowHi(string str);
        static void Main(string[] args)
        {
            //ShowHi sh = new ShowHi(ShowHi2);
            //sh("zs");


            //委託是C#中的靈魂  從軟體開發的角度講我們應該瞭解整個系統的流程(業務邏輯)
            //開發應該瞭解底層 底層:怎麼走的怎麼來的  



            //加事件用 +=  取消事件 -=
            //實際上事件的執行的規則和過程與委託一致
            //事件最終執行的內容依然是委託
            //事件和委託的關聯是因為 在定義事件的時候就會有一個委託的定義 並且事件的型別 就是當前的委託
            //1 需要例項化你的釋出器
            Hello h = new Hello();
            //2 需要例項化你的訂閱器
            Jp j = new Jp();
            USA u = new USA();
            //3 給釋出器加上訂閱器
            h.ShowHievent += new Hello.ShowHiDelegate(j.ShowHi);
            h.ShowHievent += new Hello.ShowHiDelegate(u.ShowHi);               
            //4 給釋出器去除訂閱器
            h.ShowHievent -= new Hello.ShowHiDelegate(u.ShowHi);
            //執行事件
            h.ClickShowHievent();

            Console.ReadKey();

        }

        //public static void ShowHi2(string str1)
        //{
        //    Console.WriteLine("你好"+str1);
        //    Console.ReadKey();
        //}
       
            
    }
}

三、反射

反射指程式可以訪問、檢測和修改它本身狀態或行為的一種能力。
程式集包含模組,而模組包含型別,型別又包含成員。
反射則提供了封裝程式集、模組和型別的物件。
您可以使用反射動態地建立型別的例項,將型別繫結到現有物件,或從現有物件中獲取型別。
然後,可以呼叫型別的方法或訪問其欄位和屬性。

優點:
1、反射提高了程式的靈活性和擴充套件性。
2、降低耦合性,提高自適應能力。
3、它允許程式建立和控制任何類的物件,無需提前硬編碼目標 類。

缺點:
1、效能問題:使用反射基本上是一種解釋操作,用於欄位和方 法接入時要遠慢於直接程式碼。因此反射機制主要應用在對靈 活性和拓展性要求很高的系統框架上,普通程式不建議使 用。
2、使用反射會模糊程式內部邏輯;程式設計師希望在原始碼中看到 程式的邏輯,反射卻繞過了原始碼的技術,因而會帶來維護 的問題,反射程式碼比相應的直接程式碼更復雜。

反射的用途:
1.使用Assembly定義和載入程式集,載入在程式集中的所有模 塊以及從此程式集中查詢型別並建立該型別的例項。
2.使用Module瞭解包含模組的程式集以及模組中的類等,還可 以獲取在模組上定義的所有全域性方法或其他特定的非全域性 方法。
3.使用ConstructorInfo瞭解建構函式的名稱、引數、訪問修飾 符(如pulic 或private)和實現詳細資訊(如abstract或 virtual)等。
4.使用MethodInfo瞭解方法的名稱、返回型別、引數、訪問修 飾符(如pulic 或private)和實現詳細資訊(如abstract或 virtual)等。
5.使用FiedInfo瞭解欄位的名稱、訪問修飾符(如public或 private)和實現詳細資訊(如static)等,並獲取或設定欄位 值。
6.使用EventInfo瞭解事件的名稱、事件處理程式資料型別、自 定義屬性、宣告型別和反射型別等,新增或移除事件處理 程式。
7.使用PropertyInfo瞭解屬性的名稱、資料型別、宣告型別、 反射型別和只讀或可寫狀態等,獲取或設定屬性值。
8.使用ParameterInfo瞭解引數的名稱、資料型別、是輸入引數 還是輸出引數,以及引數在方法簽名中的位置等。

反射用到的主要類:
1.System.Type 類
通過這個類可以訪問任何給定資料型別的資訊。

2.System.Reflection.Assembly 類
它可以用於訪問給定程式集的資訊,或者把這個程式集載入 到程式中。

System.Type類用法:
System.Type類對於反射起著核心的作用。但它是一個抽象的基類,Type有與每種資料型別對應的派生類,我們使用這個派生類的物件的方法、欄位、屬性來查詢有關該型別的所有資訊。獲取給定型別的Type引用有3種常用方式:
1.使用 C# typeof 運算子
2.使用物件GetType()方法
3.呼叫Type類的靜態方法GetType(“類的全路徑”)

Type類的屬性:
1.Name資料型別名
2.FullName 資料型別的完全限定名(包括名稱空間名)
3.Namespace 定義資料型別的名稱空間名
4.IsAbstract 指示該型別是否是抽象型別
5.IsArray 指示該型別是否是陣列
6.IsClass 指示該型別是否是類
7.IsEnum 指示該型別是否是列舉
8.IsInterface 指示該型別是否是介面
9.IsPublic 指示該型別是否是公有的
10.IsSealed 指示該型別是否是密封類
11.IsValueType 指示該型別是否是值型別

Type類的方法:
1.GetConstructor(), GetConstructors():
返回ConstructorInfo型別,用於取得該類的建構函式的資訊

2.GetEvent(), GetEvents():
返回EventInfo型別,用於取得該類的事件的資訊

3.GetField(), GetFields():
返回FieldInfo型別,用於取得該類的欄位(成員變數)的 資訊

4.GetInterface(), GetInterfaces():
返回InterfaceInfo型別,用於取得該類實現的介面的資訊

5.GetMember(), GetMembers():
返回MemberInfo型別,用於取得該類的所有成員的資訊

6.GetMethod(), GetMethods():
返回MethodInfo型別,用於取得該類的方法的資訊

7.GetProperty(), GetProperties():
返回PropertyInfo型別,用於取得該類的屬性的資訊

System.Reflection.Assembly類的用法:
Assembly類可以獲得程式集的資訊,也可以動態的載入程式集,以及在程式集中查詢型別資訊,並建立該型別的例項。使用Assembly類可以降低程式集之間的耦合性,有利於軟體結構的合理化。
1.通過程式集名稱返回Assembly物件
Assembly.Load(“類名”);
2.通過DLL檔名稱返回Assembly物件 Assembly.LoadFrom(@“c:\ReflectionDemo2.dll”);
3.通過Assembly獲取程式集中類
Assembly物件名.GetType(“引數必須是類的全名”);
4.通過Assembly獲取程式集中所有的類
Assembly物件名.GetTypes();

實現的程式碼:

Person類:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _11_1
{
    public class Person
    {
        //欄位
        private int _pid;
        public  string _pname;

        //屬性
        public int Pid
        {
            get
            {
                return _pid;
            }

            set
            {
                _pid = value;
            }
        }

        public string Pname
        {
            get
            {
                return _pname;
            }

            set
            {
                _pname = value;
            }
        }

        //public Person() { }

        //public Person(int _pid, string _pname)
        //{
        //    this.Pid = _pid;
        //    this.Pname = _pname;
        //}

        /// <summary>
        /// 定義好事件的委託
        /// </summary>
        public delegate void ShowHiDelegate();
        /// <summary>
        /// 定義好一個你好的事件
        /// </summary>
        public event ShowHiDelegate ShowHievent;

       
        public void PersonShow(string str)
        {
            Console.WriteLine("人"+str);
        }



    }
}

Program類(實現的類):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace _11_1
{
    class Program
    {
        static void Main(string[] args)
        {
            //Person p = new Person();
            //使用物件GetType()方法
            //Type t = p.GetType(); 
            //呼叫Type類的靜態方法GetType("類的全路徑")  像java class.fromname
            //Type t = Type.GetType("_11_1.Person");
            //資料型別名
            //Console.WriteLine(t.Name);
            //資料型別的完全限定名(包括名稱空間名)
            //Console.WriteLine(t.FullName);
            //定義資料型別的名稱空間名
            //Console.WriteLine(t.Namespace);
            //指示該型別是否是抽象型別
            //Console.WriteLine(t.IsAbstract);
            //指示該型別是否是陣列
            //Console.WriteLine(t.IsArray);
            //指示該型別是否是類
            //Console.WriteLine(t.IsClass);
            //指示該型別是否是列舉
            //Console.WriteLine(t.IsEnum);
            //指示該型別是否是介面
            //Console.WriteLine(t.IsInterface);
            //指示該型別是否是公有的
            //Console.WriteLine(t.IsPublic);
            //指示該型別是否是密封類
            //Console.WriteLine(t.IsSealed);
            //指示該型別是否是值型別
            //Console.WriteLine(t.IsValueType);
            //Console.ReadKey();

            //Type t = Type.GetType("_11_1.Person");
            //object objects =Activator.CreateInstance(t);

            //1.返回ConstructorInfo型別,用於取得該類的建構函式的資訊
            //Type[] types = new Type[0];
            //ConstructorInfo c=t.GetConstructor(types);
            //Console.WriteLine(c.IsPublic);

            //2.返回EventInfo型別,用於取得該類的事件的資訊
            //EventInfo[] ei= t.GetEvents();
            //foreach (EventInfo e in ei)
            //{
            //    Console.WriteLine(e.Name);
            //}

            //3.返回FieldInfo型別,用於取得該類的欄位(成員變數)的資訊
            //FieldInfo fi = t.GetField("_pname");
            //Person p=new Person(); p.setpname="zs";            
            //fi.SetValue(objects,"zs");
            //Console.WriteLine(fi.GetValue(objects));   

            //4.返回MemberInfo型別,用於取得該類的所有成員的資訊
            //MemberInfo[] mb=t.GetMember("ShowHiDelegate");
            //foreach (MemberInfo m in mb)
            //{
            //    Console.WriteLine(m.Name);
            //}

            //5.返回MethodInfo型別,用於取得該類的方法的資訊
            //MethodInfo[] mi=t.GetMethods();
            //foreach (MethodInfo item in mi)
            //{
            //    Console.WriteLine(item.Name);
            //}

            //6.返回PropertyInfo型別,用於取得該類的屬性的資訊
            //PropertyInfo pi =t.GetProperty("Pname");
            //set_Pname
            //pi.SetValue(objects,"zs");
            //get_Pname
            //Console.WriteLine(pi.GetValue(objects));

            //反射呼叫方法
            //MethodInfo mi=t.GetMethod("PersonShow");
            //object[] oo =new object[1];
            //oo[0] = "zs";
            //mi.Invoke(objects,oo);

            //Assembly as1=Assembly.Load("Person");
            Assembly as1 = Assembly.LoadFrom(@"D:\Visual Studio 2015\Projects\217Base\11\bin\Debug\11.dll");
            Type[] t=as1.GetTypes();
            foreach (Type item in t)
            {
                Console.WriteLine(item.Name);
            }

            Console.ReadKey();



        }
    }
}