• C# 函数扩展方法的妙用


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

  • 相关阅读:
    redis之哨兵配置-2
    redis之主从配置-1
    MYSQL 在当前时间加上或减去一个时间段
    【转】将long数字序列化为json时,转换为字符串
    从技术到产品,从职场到创业,我这7年的痕迹
    可能是东半球第二好用的软件工具全部在这里(update in 2020.10.09)
    Java架构师面试题答案2020备忘录
    学习方法
    《精力管理》管理精力,而非时间
    《道德经》全文
  • 原文地址:https://www.cnblogs.com/tiancaiwrk/p/13438561.html
Copyright © 2020-2023  润新知