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 来判断, 想要这个功能的正确实现, 只有经过修改语法树的方法来尝试了...

相关文章
相关标签/搜索