擴展方法 Extension Method 我們很多時候都是考慮方便性才去添加的, 系統庫也有很多, 像 Linq / Expression 之類的, 使用起來就像是給物件添加了一個成員函式一樣 :
官方例子
namespace ExtensionMethods { public static class IntExtensions { public static bool IsGreaterThan(this int i, int value) { return i > value; } } }
using ExtensionMethods; class Program { static void Main(string[] args) { int i = 10; bool result = i.IsGreaterThan(100); Console.WriteLine(result); } }
看到擴展的函式呼叫就像成員變數一樣, 不過真的是這樣嗎? 看看下面的代碼 :
using UnityEngine; using System; public class Test : MonoBehaviour { private System.Action aCall = null; private void Start() { aCall.Call(); } } public static class Ext { public static void Call(this System.Action action) { if(action != null) { action.Invoke(); } } }
斷點看, 能夠進來 :

那么它提供的擴展就不是代碼層面的, 是編譯層面的了, 在編譯上所有的方法都是靜態的, 只是在呼叫的時候傳入了呼叫物件, 而成員函式只是在上面進行的封裝, 從反射的Method.Invoke() 就能看到實體需要傳入物件才能正確呼叫 :
public object Invoke(object obj, object[] parameters)
其實它的代碼等效于 :
aCall.Call(); // 等于 Ext.Call(aCall);
所以就算看起來是成員函式呼叫, 其實是靜態呼叫, 所以即使物件 aCall 是空, 也是可以運行的, 對于 Unity 來說, 很多時候會發生非預期的物件洗掉, 或者洗掉后仍然存在的現象, 每次都需要判空, 就像一個 UI 上的 Text 這樣 :
public class Test : MonoBehaviour { public Text title; public void SetTitle(string info) { if(title) { title.text = info; } } }
這樣只在功能內寫判空的就比較累人, 不如寫個靜態方法 :
public class Test : MonoBehaviour { public UnityEngine.UI.Text title; } public static class Ext { public static void SetTextUI(UnityEngine.UI.Text text, string info) { if(text) { text.text = info; } } } //... Text textUI; Ext.SetTextUI(textUI, "xxx");
不過現在發現擴展方法的呼叫也是靜態呼叫, 空物件也能運行, 那就寫成擴展就更方便了 :
public static class Ext { public static void SetTextUI(this UnityEngine.UI.Text text, string info) { if(text) { text.text = info; } } } //... Text textUI; textUI.SetTextUI("xxx");
這就是擴展方法的好處了, 它不是代碼層面的添加了一個成員函式.
還有一個現在用 C# 6.0 以上語法的話, 可以直接判空 :
Text textUI; textUI?.text = "xxx";
可是對于 Unity Object 物件, 這樣的判空相當于 :
Text textUI; if(textUI != null) { textUI.text = "xxx"; }
這樣判空是不對的, 必須使用它的隱式轉換 bool 來判斷, 想要這個功能的正確實作, 只有通過修改語法樹的方法來嘗試了...
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/79448.html
標籤:其他
上一篇:入門小白想請教python問題
