.Net程式員學用Oracle系列(25):觸發器詳解

来源:http://www.cnblogs.com/hanzongze/archive/2017/05/15/Oracle-Trigger.html
-Advertisement-
Play Games

" 1、觸發器理論 " "1.1、觸發器的應用場景" "1.2、觸發器的類型" "1.3、DML 觸發器的觸發順序" " 2、觸發器實戰 " "2.1、創建觸發器" "2.1.1、創建 DML 觸發器" "2.1.2、創建 DDL 觸發器" "2.1.3、創建事件觸發器" "2.2、調試觸發器" " ...


1、觸發器理論

1.1、觸發器的應用場景

在 Oracle 中,事件或語句都能觸發觸發器,這也正是觸發器的用武之地,具體來說有以下 4 類可以觸發觸發器的語句或事件:

  • 1、DML 語句,用於修改特定表或視圖中數據的 INSERT、UPDATE、DELETE 等語句。
  • 2、DDL 語句,主要是 CREATE、ALERT 等常見 DDL 語句。
  • 3、系統事件,如啟動或關閉資料庫實例、錯誤消息等。
  • 4、用戶事件,如登錄或註銷。

觸發器通常用來執行複雜的業務規則,用於實現由資料庫完整性約束難以實現的約束,或用來自動生成分配列值、維護表數據同步、在分散式資料庫中的節點之間強制引用完整性、防止無效操作、提供審計、監控對資料庫的各種操作、提供透明的事件記錄、當對視圖發出 DML 語句時修改表數據等。

在項目中應儘可能少的使用觸發器,因為過多使用觸發器可能會導致複雜的相互依賴關係,這在很大的應用程式中是難以維護的。例如,當某個觸發器被觸發後,該觸發器中的 SQL 語句又觸發了其它的觸發器,也就是級聯觸發,這可能會導致一些無法預見的影響。

儘管可以同時使用觸發器和完整性約束來定義實施任何類型的完整性規則。但 Oracle 強烈建議僅在以下兩種情況下使用觸發器來約束數據輸入:

  • 1、執行使用完整性約束難以實現的複雜業務規則。
  • 2、當子表和父表位於分散式資料庫的不同節點時,執行引用完整性。

1.2、觸發器的類型

在 Oracle 的官方手冊中將觸發器分為 4 類,分別是:行級觸發器和語句級觸發器、BEFORE 觸發器和 AFTER 觸發器、INSTEAD OF 觸發器、事件觸發器。另外,行級觸發器和語句級觸發器與 BEFORE 觸發器和 AFTER 觸發器還可以兩兩組合形成 4 種複合型的 DML 觸發器。

1、行級觸發器和語句級觸發器

定義觸發器時可以指定觸發條件和觸發頻次。觸發器條件是指由 WHEN 子句指定的一個邏輯表達式,當該表達式結果為 TRUE 時才會執行觸發器。行級觸發器的運行次數與受影響的行數相關,而語句級觸發器在被觸發後只運行一次。

行級觸發器:觸發語句每影響一行觸發一次行級觸發器。例如,UPDATE 表中多個行,則會對 UPDATE 語句影響的每一行觸發一次行級觸發器。如果觸發語句不影響行,則不會運行行級觸發器。如果觸發操作中的代碼取決於觸發語句或需要訪問受影響行的數據,則行級觸發器很有用。

語句級觸發器:無論觸發語句會影響表中多少行,即使沒有行受到影響,語句級觸發器也會被觸發一次。例如,DELETE 表中多個行,則會對 DELETE 語句影響的表觸發一次語句級觸發器。如果觸發器操作中的代碼不依賴於觸發語句和受影響的行的數據,則語句級觸發器很有用。

2、BEFORE 觸發器和 AFTER 觸發器

定義觸發器時可以指定觸發時機,具體來說就是可以指定是在觸發事件之前還是之後執行。DML 語句觸發的 BEFORE 觸發器和 AFTER 觸發器只能在表上定義,不能在視圖上定義。如果用戶執行了針對視圖的 DML 語句,則會觸發視圖基表上的觸發器。DDL 語句觸發的 BEFORE 觸發器和 AFTER 觸發器只能在資料庫或模式上定義,而不能在特定的表上定義。

BEFORE 觸發器:在觸發語句運行之前運行觸發器操作。當需要根據情況確定是否允許觸發語句執行或需要在完成觸發操作之前導出特定的數據時,BEFORE 觸發器很有用。

AFTER 觸發器:在觸發語句運行之後運行觸發器操作。AFTER 觸發器主要用於執行那些必須在觸發操作之後才能執行的操作。

3、INSTEAD OF 觸發器

INSTEAD OF 觸發器提供了一種透明的方式來修改不能通過 DML 語句直接修改的視圖。這些觸發器也被稱為替代觸發器,與其它類型觸發器不同的是,替代觸發器由 Oracle 觸發而不是執行觸發語句。可以針對視圖編寫正常的 DML 語句,並觸發 INSTEAD OF 觸發器適當的更新基表中的數據。

4、事件觸發器

事件觸發器可以被系統事件或用戶事件觸發。可以觸發事件觸發器的事件有:資料庫的啟動和關機、伺服器錯誤消息事件、用戶登錄和註銷、執行 DDL 語句、執行 DML 語句等。

1.3、DML 觸發器的觸發順序

DML 觸發器的類型比較多,當單個 SQL 語句觸發了多個觸發器時,Oracle 會按照既定的順序依次運行每種類型的觸發器。具體執行順序如下:

  • 1、執行 BEFORE 語句級的觸發器。
  • 2、遍歷所有行受 DML 語句影響。
  • 3、執行 BEFORE 行級的觸發器。
  • 4、鎖定行,並執行觸發觸發器的 DML 語句,同時執行完整性約束檢查,鎖定在事務提交之前不能被釋。
  • 5、執行 AFTER 行級的觸發器。
  • 6、完成延遲的完整性約束檢查。
  • 7、執行 AFTER 語句級的觸發器。

Oracle 針對不同類型的觸發器在設定的時間點執行完整性約束檢查,並保證觸發器不會危及完整性約束。如果給定的語句觸發了多個相同類型的觸發器,Oracle 將以未指定的隨機順序觸發多個觸發器;也就是說,相同語句的相同類型的觸發器不能保證以任何特定的順序觸發。所以不應該重覆定義觸發器。

2、觸發器實戰

2.1、創建觸發器

可以在資料庫級別或模式級別定義系統事件觸發器。DDL 語句或登錄/註銷事件觸發器也可以在資料庫級別或模式級別進行定義。可以在表或視圖上定義 DML 語句的觸發器。在資料庫級別定義的觸發器對所有用戶公開,並且只有當觸發事件涉及該模式或表時,才會觸發在模式或表級別定義的觸發器。

在觸發器中,允許訪問觸發事件的某些屬性。例如,資料庫啟動和關閉觸發器具有的實例編號和資料庫名稱,登錄和註銷觸發器具有的用戶名,DML 語句上的觸發器具有的 OLD 列值和 NEW 列值等。

另外,在創建觸發器時還需要註意以下事項:

  • 1、即便在編譯觸發器期間發生了錯誤,仍然會創建觸發器。所以創建觸發器之後應該要再檢查下觸發器的狀態,確定其是否真的可用。
  • 2、觸發器不能有參數。這個也好理解,因為不方便傳參。
  • 3、如果要在觸發器中使用 SELECT 語句,那麼只能是 SELECT ... INTO ... 結構或結合顯示游標使用。簡而言之,Oracle 觸發器不支持標準的 SELECT 語句。
  • 4、在觸發器中預設可以直接用 DML 語句,但不能直接用 DDL 語句和事務控制語句。被觸發器調用的存儲過程也不能直接使用事務控制語句。因為觸發器和觸發語句在同一個事務中,當觸發語句被提交或回退時,觸發器也將被提交或回退。不註意這點可能會遇到一些莫名其妙的問題。
  • 5、在觸發器中不能使用 LONG 和 LONG RAW 類型,可以使用 LOB 類型,但不可以修改 LOB 類型的列值。
  • 6、定義觸發器的代碼不能超過 32K。如果觸發邏輯比較複雜的話,應將大部分代碼放到存儲過程中,再從觸發器中調用存儲過程。
2.1.1、創建 DML 觸發器

語法:

CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE | AFTER} -- 指定觸發時機
{INSERT | DELETE | UPDATE [OF column1 [,column2 ...]]} -- 指定觸發事件
ON [SCHEMA.]table_name -- 指定觸發對象
[REFERENCES {OLD [AS] old_name | NEW [AS] new_name | PARENT [AS] parent_name}]
[FOR EACH ROW] -- 指定為行級觸發器,不指定預設為語句級觸發器
[WHEN condition] -- 指定觸發條件,只有行級觸發器才能指定觸發條件
DECLARE
  -- 定義變數
BEGIN
  -- 觸發器操作代碼
EXCEPTION
  WHEN ...
  -- 異常處理代碼
END [trigger_name];

BEFORE INSERT 觸發器

示例:

CREATE OR REPLACE TRIGGER trg_bi
BEFORE INSERT ON demo.t_course
FOR EACH ROW
DECLARE
  v_today DATE;
BEGIN
  v_today := SYSDATE;
  :NEW.course_desc := '創建於 '||TO_CHAR(SYSDATE,'yyyy-mm-dd')||'。'||:NEW.course_desc;
END;

測試:

INSERT INTO demo.t_course VALUES(6,'電腦英語','電腦專業英語課程');

BEFORE UPDATE 觸發器

示例:

CREATE OR REPLACE TRIGGER trg_bu
BEFORE UPDATE ON demo.t_course
FOR EACH ROW
DECLARE
  v_today DATE;
BEGIN
  v_today := SYSDATE;
  IF :NEW.course_name != :OLD.course_name THEN
    :NEW.course_desc := '修改於 '||TO_CHAR(SYSDATE,'yyyy-mm-dd')||'。'||:NEW.course_desc;
  END IF;
END;

測試:

UPDATE demo.t_course t SET t.course_name='電腦英語(下冊)' WHERE t.course_id=6;

BEFORE DELETE 觸發器

示例:

CREATE OR REPLACE TRIGGER trg_bd
BEFORE DELETE ON demo.t_course
FOR EACH ROW -- FOR EACH ROW 必須要在 WHEN 字句之前,否則無法創建觸發器
WHEN (OLD.course_id > 0) -- 此處 OLD 前面不能帶冒號,與 PL/SQL 塊中額寫法相反
DECLARE
  v_today DATE;
  v_username VARCHAR2(20);
BEGIN
  v_today := SYSDATE;
  SELECT USER INTO v_username FROM DUAL;
  
  -- 將正式的課程數據備份到備份表
  INSERT INTO t_course_backup(course_id, course_name, course_desc, delete_date, deleted_by)
  VALUES(:OLD.course_id, :OLD.course_name, :OLD.course_desc, v_today, v_username);
END;

測試:

DELETE FROM demo.t_course t WHERE t.course_id=6;

AFTER INSERT & UPDATE & DELETE 觸發器

示例:

CREATE OR REPLACE TRIGGER trg_aiud
AFTER INSERT OR UPDATE OR DELETE ON demo.t_course
FOR EACH ROW
DECLARE
  v_today DATE;
  v_username VARCHAR2(20);
BEGIN
  v_today := SYSDATE;
  SELECT USER INTO v_username FROM DUAL;
  
  -- 根據不同觸發語句,執行不同備份操作
  IF INSERTING THEN -- 當添加事件被觸發時
    INSERT INTO t_course_backup(course_id, course_name, course_desc, insert_date, inserted_by)
    VALUES(:NEW.course_id, :NEW.course_name, :NEW.course_desc, v_today, v_username);
  ELSIF UPDATING THEN -- 當修改事件被觸發時
    INSERT INTO t_course_backup(course_id, course_name, course_desc, update_date, updated_by)
    VALUES(:OLD.course_id, :OLD.course_name, :OLD.course_desc, v_today, v_username);
  ELSIF DELETING THEN -- 當刪除事件被觸發時
    INSERT INTO t_course_backup(course_id, course_name, course_desc, delete_date, deleted_by)
    VALUES(:OLD.course_id, :OLD.course_name, :OLD.course_desc, v_today, v_username);
  END IF;
END;

測試:

INSERT INTO demo.t_course VALUES(8,'微積分','高等數學');
UPDATE demo.t_course t SET t.course_name='微積分入門' WHERE t.course_id=8;
DELETE FROM demo.t_course t WHERE t.course_id=8;
2.1.2、創建 DDL 觸發器

示例:

CREATE OR REPLACE TRIGGER trg_ddl_oper
/**************************************************
功能:監控資料庫的 DDL 操作,阻止所有針對 demo 的 DLL 操作(此處僅為示例,無實際意義)

修訂記錄:
版本號    修訂時間      修訂人    描述
1.0.0     2017-05-12    hanzz     1.創建此觸發器
**************************************************/
BEFORE DDL ON demo.SCHEMA -- 還可以指定為某一種 DDL 或 DATABASE
DECLARE
  event VARCHAR2(30);
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
  event := ORA_SYSEVENT; -- 接收觸發事件
  
  INSERT INTO demo.t_ddl_log(trg_event, obj_owner, obj_name, user_name, attempt_time)
  SELECT event,ORA_DICT_OBJ_OWNER,ORA_DICT_OBJ_NAME,USER,SYSTIMESTAMP FROM DUAL;
  COMMIT;
  
  IF event = 'CREATE' THEN
    RAISE_APPLICATION_ERROR(-20001,'禁止創建對象!');
  ELSIF event = 'DROP' THEN
    RAISE_APPLICATION_ERROR(-20002,'禁止刪除對象!');
  ELSIF event = 'TRUNCATE' THEN
    RAISE_APPLICATION_ERROR(-20003,'禁止清空表!');
  ELSIF event = 'COMMENT' THEN
    RAISE_APPLICATION_ERROR(-20004,'禁止修改註釋!');
  ELSE
    RAISE_APPLICATION_ERROR(-20001,'禁止 '||ORA_SYSEVENT||' 操作!');
  END IF;
END;
2.1.3、創建事件觸發器

1、禁止通過 PL/SQL Developer 來登錄 SCOTT 用戶

CREATE OR REPLACE TRIGGER trg_deny_plsqldev
AFTER LOGON ON DATABASE
DECLARE
  v_program VARCHAR2(50);
  v_username VARCHAR2(50);
BEGIN
  SELECT t.program,t.username INTO v_program,v_username FROM V$SESSION t 
  WHERE t.audsid=SYS_CONTEXT('USERENV','SESSIONID') AND ROWNUM=1;
  
  IF LOWER(v_program)='plsqldev.exe' AND v_username='SCOTT' THEN
    RAISE_APPLICATION_ERROR(-20000,'It is forbidden to login SCOTT via PL/SQL Developer!');
  END IF;
END;

2、限制指定用戶和指定 IP 登錄

CREATE OR REPLACE TRIGGER trg_deny_login
AFTER LOGON ON DATABASE
DECLARE
  v_ip VARCHAR2(20);
  v_message VARCHAR2(500);
  v_deny_user_exception EXCEPTION;
  v_deny_ip_exception EXCEPTION;
BEGIN
  v_ip := SYS_CONTEXT('USERENV','IP_ADDRESS');
  INSERT INTO demo.t_login_his(user_name, login_time, login_ip) VALUES(USER,SYSTIMESTAMP,v_ip);
  COMMIT;
  
  IF USER IN('SCOTT','DEMO') THEN
    RAISE v_deny_user_exception;
  END IF;
  
  IF v_ip = '127.0.0.1' THEN
    RAISE v_deny_ip_exception;
  END IF;
  
  EXCEPTION
    WHEN v_deny_user_exception THEN
      v_message := '禁止使用 SCOTT 等用戶登錄資料庫!';
      RAISE_APPLICATION_ERROR(-20001,v_message);
    WHEN v_deny_ip_exception THEN
      v_message := '禁止在 127.0.0.1 上登錄資料庫!';
      RAISE_APPLICATION_ERROR(-20001,v_message);
END;

上面兩個限制登錄的觸發器設計思路都是:捕獲到拒絕登錄的用戶、IP 或應用程式就拋出應用異常強制用戶退出登錄。因此它們的缺陷也是一樣的,首先,如果用戶具有 DBA 的許可權,觸發器就不起作用了;其次,如果用戶通過 SQLPlus 登錄,SYS_CONTEXT('USERENV','IP_ADDRESS')就會返回空。

2.2、調試觸發器

在 PL/SQL Developer 中,調試存儲過程的功能還蠻好用的,直接在存儲過程名稱上右鍵,然後點測試即可進入調試視窗,接下來就可以調試了。而觸發器似乎是不能調試的,因為觸發器的右鍵菜單中沒有測試選項,其實不然!根本原因在於觸發器和存儲過程的調用方式不同,用戶是無法直接調用觸發器的,只能由 Oracle 系統來調用,但用戶可以模擬觸發的動作,讓 Oracle 系統自動去調用。

下麵就拿trg_aiud來舉例說明該如何調試觸發器:

  • 第一步:在觸發器名稱上右鍵,點擊添加調試信息。註意:這一步非常重要,如果不添加調試信息,就不能單步調試了,這樣也就沒有調試的意義了。
  • 第二步:新建一個測試視窗,在測試視窗中寫出能夠觸發觸發器的語句。且要以 PL/SQL 塊的形式,即將語句寫在 BEGIN ... END 之間。
  • 第三步:按F9或者點擊開始調試器,即可進入調試模式。接下來你可以按Ctrl+N單步進入或Ctrl+O單步跳過,需要的話也可以Ctrl+R運行到底。當然也可以點調試視窗上面的那幾個菜單按鈕,事實上我一般都是點按鈕(因為 PL/SQL Developer 的快捷鍵實在太不好用了)。

2.3、禁用和啟用觸發器

ALTER TRIGGER trg_aiud DISABLE; -- 禁用名為 trg_aiud 的觸發器
ALTER TRIGGER trg_aiud ENABLE;  -- 啟用名為 trg_aiud 的觸發器
ALTER TABLE t_course DISABLE ALL TRIGGERS; -- 禁用 t_course 表上所有的觸發器
ALTER TABLE t_course ENABLE ALL TRIGGERS;  -- 啟用 t_course 表上所有的觸發器

3、總結

本文從理論和實戰兩個方面講述了 Oracle 觸發器的方方面面,唯獨沒有涉及替代觸發器,只因前文《.Net程式員學用Oracle系列(23):視圖理論、物化視圖:可更新的連接視圖》中已經講過。最後,我再重申一遍,除非是某些特殊情況,否則儘可能不用觸發器,因為用多了可能會導致項目難以維護。

本文鏈接http://www.cnblogs.com/hanzongze/p/Oracle-Trigger.html
版權聲明:本文為博客園博主 韓宗澤 原創,作者保留署名權!歡迎通過轉載、演繹或其它傳播方式來使用本文,但必須在明顯位置給出作者署名和本文鏈接!本人初寫博客,水平有限,若有不當之處,敬請批評指正,謝謝!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 摘要: 1、在mysql中執行下句成功,可添加中文的。insert into book(bookName,author,publish) values('好','hao','hao'); 但是在jsp中執行這個insert 語句就會出現亂碼。 1、在mysql中執行下句成功,可添加中文的。 inse ...
  • 3. Yarn-Cluster Yarn是一種統一資源管理機制,可以在上面運行多種計算框架。Spark on Yarn模式分為兩種:Yarn-Cluster和Yarn-Client,前者Driver運行在Worker節點,後者Driver運行在Client節點上。採用Spark on Yarn模式, ...
  • 進程的狀態轉換 在說明SOS_SCHEDULER_YIELD等待之前,先簡要介紹一下進程的狀態(迷迷糊糊記得操作系統原理課上講過,三態五態轉換的,比下麵這個圖要複雜,大部分都還給老師了)。 如下圖,分別是:運行態,阻塞態,就緒態。各個狀態之間的轉換關係及粗略原因如下: 運行態-->阻塞態,原因:等待 ...
  • 在學習段(segment)、區間(extent)時,對段的HEADER_BLOCK有一些疑問,本文記錄一下探究的實驗過程以及相關總結,,如有不對的地方,敬請指出。以SCOTT.EMP表為例(下麵測試環境為Oracle Database 10g Release 10.2.0.5.0 - 64bit P... ...
  • Spark一共有5種運行模式:Local,Standalone,Yarn-Cluster,Yarn-Client和Mesos。 1. Local Local模式即單機模式,如果在命令語句中不加任何配置,則預設是Local模式,在本地運行。這也是部署、設置最簡單的一種模式 2. Standalone ...
  • HDFS 架構簡述 Hadoop分散式文件系統(HDFS)是一個分散式的文件系統,運行在廉價的硬體上。它與現有的分散式文件系統有很多相似之處。然而與其他的分散式文件系統的差異也是顯著的。HDFS是高容錯的,被設計成在低成本硬體上部署。HDFS為應用數據提供高吞吐量的訪問,適用於具有大規模數據集的應用 ...
  • 一、關聯分析的基本概念 關聯分析(Association Analysis):在大規模數據集中尋找有趣的關係。 頻繁項集(Frequent Item Sets):經常出現在一塊的物品的集合。 關聯規則(Association Rules):暗示兩個物品之間可能存在很強的關係。 支持度(Support ...
  • 如果想在一臺電腦上搭建一個多節點的Hadoop集群,傳統的方式是使用多個虛擬機。但這種方式占用的資源比較多,一臺筆記本能同時運行的虛擬機的數量是很有限的。這個時候我們可以使用Docker。Docker可以看做是一種輕量級的虛擬機,占用資源少,用起來和傳統的虛擬機很像,使用的時候可以類比VMware或 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...