C# 函數擴展方法的妙用

  擴展方法 Extension Method 咱們不少時候都是考慮方便性纔去添加的, 系統庫也有不少, 像 Linq / Expression 之類的, 使用起來就像是給對象添加了一個成員函數同樣 : 函數

官方例子this

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);
    }
}

  看到擴展的函數調用就像成員變量同樣, 不過真的是這樣嗎? 看看下面的代碼 : spa

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();
        }
    }
}

  斷點看, 可以進來 : code

  那麼它提供的擴展就不是代碼層面的, 是編譯層面的了, 在編譯上全部的方法都是靜態的, 只是在調用的時候傳入了調用對象, 而成員函數只是在上面進行的封裝, 從反射的Method.Invoke() 就能看到實例須要傳入對象才能正確調用 : 對象

public object Invoke(object obj, object[] parameters)

  其實它的代碼等效於 : blog

aCall.Call();
// 等於
Ext.Call(aCall);

  因此就算看起來是成員函數調用, 實際上是靜態調用, 因此即便對象 aCall 是空, 也是能夠運行的, 對於 Unity 來講, 不少時候會發生非預期的對象刪除, 或者刪除後仍然存在的現象, 每次都須要判空, 就像一個 UI 上的 Text 這樣 : string

public class Test : MonoBehaviour
{    
    public Text title;
    public void SetTitle(string info)
    {
        if(title)
        {
            title.text = info;
        }
    }
}

  這樣只在功能內寫判空的就比較累人, 不如寫個靜態方法 : it

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");

  不過如今發現擴展方法的調用也是靜態調用, 空對象也能運行, 那就寫成擴展就更方便了 : io

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 來判斷, 想要這個功能的正確實現, 只有經過修改語法樹的方法來嘗試了...

相關文章
相關標籤/搜索