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

  • 相关阅读:
    Centos 6 安装python2.7.6
    更新centos系统的python版本
    centos中wget的使用方法
    开启apahce的mod_speling.so模块,让使用apahce http服务器不再有大小写烦恼
    开启server-status失败
    TCP三次握手与四次挥手
    GitHub入门和项目托管
    使用javac,手动编译一个java文件的方法
    《TomCat与Java Web开发技术详解》(第二版) 第四章节的学习总结--常用Servlet API
    《TomCat与Java Web开发技术详解》(第二版) 第三章节的学习总结--利用Context元素来自定义web应用的存储位置
  • 原文地址:https://www.cnblogs.com/tiancaiwrk/p/13438561.html
Copyright © 2020-2023  润新知