Unity 遊戲框架搭建 2019 (二十五) 類的第一個作用 與 Obselete 屬性

  • 2020 年 4 月 10 日
  • 筆記

在上一篇我們整理到了第七個示例,我們今天再接著往下整理。我們來看第八個示例:

#if UNITY_EDITOR  using UnityEditor;  #endif    using UnityEngine;  using System;  using System.IO;    namespace QFramework  {  	public class PreviousFunctions : MonoBehaviour  	{  		public static string GenerateUnityPackageName()  		{  			return "QFramework_" + DateTime.Now.ToString("yyyyMMdd_hh");  		}    		public static void CopyText(string text)  		{  			GUIUtility.systemCopyBuffer = text;  		}    		public static void OpenInFolder(string folderPath)  		{  			Application.OpenURL("file:///" +  folderPath);  		}    #if UNITY_EDITOR  		public static void CallMenuItem(string menuPath)  		{  			EditorApplication.ExecuteMenuItem(menuPath);  		}    		public static void ExportPackage(string assetPathName,string fileName)  		{  			AssetDatabase.ExportPackage(assetPathName, fileName, ExportPackageOptions.Recurse);  		}  #endif    #if UNITY_EDITOR  		[MenuItem("QFramework/8.總結之前的方法/1.獲取文件名")]  		private static void MenuClicked()  		{  			Debug.Log(GenerateUnityPackageName());  		}    		[MenuItem("QFramework/8.總結之前的方法/2.複製文本到剪切板")]  		private static void MenuClicked2()  		{  			CopyText("要複製的關鍵字");  		}    		[MenuItem("QFramework/8.總結之前的方法/3.生成文件名到剪切板")]  		private static void MenuClicked3()  		{  			CopyText(GenerateUnityPackageName());  		}    		[MenuItem("QFramework/8.總結之前的方法/4.導出 UnityPackage")]  		private static void MenuClicked4()  		{  			ExportPackage("Assets/QFramework",GenerateUnityPackageName() + ".unitypackage");  		}    		[MenuItem("QFramework/8.總結之前的方法/5.打開所在文件夾")]  		private static void MenuClicked5()  		{  			OpenInFolder(Application.dataPath);  		}    		[MenuItem("QFramework/8.總結之前的方法/6.MenuItem 復用")]  		private static void MenuClicked6()  		{  			CallMenuItem("QFramework/8.總結之前的方法/4.導出 UnityPackage");  			OpenInFolder(Path.Combine(Application.dataPath, "../"));  		}    		[MenuItem("QFramework/8.總結之前的方法/7.自定義快捷鍵")]  		private static void MenuClicked7()  		{  			Debug.Log("%e 意思是快捷鍵 cmd/ctrl + e");  		}  #endif  	}   }  

其實程式碼量還是比較多的。

而在上一篇中,我們就知道了,這個示例有類命名的問題。我們運氣比較好,剛好可以試著解決一下。

關於類,我們在寫第一個示例的時候就去接觸了,不過筆者並沒有講它,是因為作為一個程式碼設計的工具,類是非常重要的一個概念,它比方法複雜得多,不過今天我們不用全部了解,只需要了解對本示例有用的部分就好了。

我們都知道,在 C# 中方法都是需要在類中實現的。所以類的第一個作用就是方法的集合。

而我們的問題是,對於 OpenInFinder 、ExportPackage 這些方法所在的類的名字比較奇怪。

之所以能意識到問題的存在,是因為筆者知道一個庫不可能僅僅這幾個方法的。如果是僅僅這幾個方法,我們還是可以叫 PreviousFunctions 。因為方法數量比較小,所以用人腦就可以記住了。就算忘記了再去看一遍也很容易記住的。但是到目前為止我們收集了 13 個示例,那麼至少有 13 個方法,在未來隨著時間增長,我們要收集的方法會越來越多。所以給方法進行合理地分類,並把它們放在合適的地方是必須要做的。

不過我們對於對方法分類還是新手,因為到目前為止,筆者沒有在此專欄中提過方法分類這件事,

我們先來看下這些方法是幹嘛的,以及用在哪裡的?

  1. GenerateUnityPackageName:自動生成文件名,是屬於導出功能的一部分,屬於訂製方法。
  2. CopyText:複製文本,比較通用。
  3. OpenInFolder:打開所在文件夾,在 UnityEditor 里比較通用。
  4. CallMenuItem:復用菜單,在 UnityEditor 里比較通用。
  5. ExportPackage:導出 Package,在 UnityEditor 比較通用。

很自然地,根據用處可以分為三類,一個是訂製方法,GenerateUnityPackageName,它只能用在導出功能里。在其他的情況下很少適用。

第二種則是 UnityEditor 通用,比如 OpenInFolder 和 CallMenuItem。
第三種則是可能全平台通用的,比如 CopyText。

基於以上我們就按照這種方式去分類。如何分呢?

答案就是使用類,給類起一個類型名字就好。

在之前我們提過,類的第一個作用是方法的集合,它可以放若干個方法。而我們方法已經分好類型了,現在就差給類起一個合適的名字。我們先叫做 Exporter (導出器) 、EditorUtil (編輯器工具)和 CommonUtil (通用工具)。

程式碼如下:
CommonUtil 類

	public class CommonUtil  	{  		public static void CopyText(string text)  		{  			GUIUtility.systemCopyBuffer = text;  		}  	}  

Exporter 類

	public class Exporter  	{  		public static string GenerateUnityPackageName()  		{  			return "QFramework_" + DateTime.Now.ToString("yyyyMMdd_hh");  		}  	}  

EditorUtil 類

	public class EditorUtil  	{  #if UNITY_EDITOR  		public static void CallMenuItem(string menuPath)  		{  			EditorApplication.ExecuteMenuItem(menuPath);  		}    		public static void OpenInFolder(string folderPath)  		{  			Application.OpenURL("file:///" + folderPath);  		}    		public static void ExportPackage(string assetPathName,string fileName)  		{  			AssetDatabase.ExportPackage(assetPathName, fileName, ExportPackageOptions.Recurse);  		}  #endif  	}  

這樣就算給方法分好類了,這三個類放在了 PreviousFunctions 類定義位置的上方。
如下程式碼所示:

#if UNITY_EDITOR  using UnityEditor;  #endif    using UnityEngine;  using System;  using System.IO;    namespace QFramework  {  	public class CommonUtil  	{  		...  	}    	public class Exporter  	{  		...  	}    	public class EditorUtil  	{  		...  	}    	public class PreviousFunctions : MonoBehaviour  	{  		...  	}   }  

那麼,PreviousFunctions 里以前實現的方法怎麼辦?要進行刪除嘛?

已經刪了的童鞋可能知道,直接刪除會造成編譯問題。因為在第七個示例里,已經用了 PreviousFunctions 里的方法。所以保險起見,不能馬上進行刪除,而是做一步方法的中轉。
例如 PreviousFunction.CopyText 實現如下所示:

		public static void CopyText(string text)  		{  			CommonUtil.CopyText(text);  		}  

這樣就可以了,ok 了,我們把其他的部分也照著這樣做,程式碼如下。

		public static string GenerateUnityPackageName()  		{  			return Exporter.GenerateUnityPackageName();  		}    		public static void CopyText(string text)  		{  			CommonUtil.CopyText(text);  		}    		public static void OpenInFolder(string folderPath)  		{  			EditorUtil.OpenInFolder((folderPath));  		}    #if UNITY_EDITOR  		public static void CallMenuItem(string menuPath)  		{  			EditorUtil.CallMenuItem(menuPath);  		}    		public static void ExportPackage(string assetPathName,string fileName)  		{  			EditorUtil.ExportPackage(assetPathName, fileName);  		}  #endif  

這樣,可以保證功能不失效,也就是遵循了我們的約定和規則之一。

但是這樣還不夠,因為我們逐個整理完示例之後,回過頭來可能會忘記。在這裡筆者介紹一個 C# 的標籤屬性 [System.Obselete(「方法以過時」)] ,只要在方法上加上這個標籤,編譯器就會在使用這個方法的地方報出警告,而警告的內容則是 Obselete 括弧中的 「方法以過時」。

我們先給這五個方法加上,然後觀察下 Unity 的控制台的警告。

程式碼如下:
PreviousFunctions.cs

		[Obsolete("方法以過時,請使用 Exporter.GenerateUnityPackageName();")]  		public static string GenerateUnityPackageName()  		{  			return Exporter.GenerateUnityPackageName();  		}    		[Obsolete("方法以過時,請使用 CommonUtil.CopyText(text);")]  		public static void CopyText(string text)  		{  			CommonUtil.CopyText(text);  		}    		[Obsolete("方法以過時,請使用 EditorUtil.OpenInFolder(folderPath);")]  		public static void OpenInFolder(string folderPath)  		{  			EditorUtil.OpenInFolder(folderPath);  		}    #if UNITY_EDITOR  		[Obsolete("方法以過時,請使用 EditorUtil.CallMenuItem(menuPath);")]  		public static void CallMenuItem(string menuPath)  		{  			EditorUtil.CallMenuItem(menuPath);  		}    		[Obsolete("方法以過時,請使用 EditorUtil.ExportPackage(assetPathName, fileName);"]  		public static void ExportPackage(string assetPathName,string fileName)  		{  			EditorUtil.ExportPackage(assetPathName, fileName);  		}  #endif  

編譯之後的結果如下:
006tNc79gy1fzfr5lhb4tj30k00l4428.jpg

資訊給得非常詳細,這樣我們之後就不會忘記了,只要在方法上有 Obsolete 的方法,在進行整理的時候如果它沒有被引用的時候就可以刪掉了。

現在這幾個方法被第七個示例引用了,所以還不能刪除,而是這一輪示例整理過後,回過頭再整理。

今天新的內容夠多了,我們直接列出完整的 PreviousFuctions.cs 程式碼。

如下:

#if UNITY_EDITOR  using UnityEditor;  #endif    using UnityEngine;  using System;  using System.IO;    namespace QFramework  {  	public class CommonUtil  	{  		public static void CopyText(string text)  		{  			GUIUtility.systemCopyBuffer = text;  		}  	}    	public class Exporter  	{  		public static string GenerateUnityPackageName()  		{  			return "QFramework_" + DateTime.Now.ToString("yyyyMMdd_hh");  		}  	}    	public class EditorUtil  	{  #if UNITY_EDITOR  		public static void CallMenuItem(string menuPath)  		{  			EditorApplication.ExecuteMenuItem(menuPath);  		}    		public static void OpenInFolder(string folderPath)  		{  			Application.OpenURL("file:///" + folderPath);  		}    		public static void ExportPackage(string assetPathName,string fileName)  		{  			AssetDatabase.ExportPackage(assetPathName, fileName, ExportPackageOptions.Recurse);  		}  #endif  	}    	public class PreviousFunctions : MonoBehaviour  	{  		[Obsolete("方法以過時,請使用 Exporter.GenerateUnityPackageName();")]  		public static string GenerateUnityPackageName()  		{  			return Exporter.GenerateUnityPackageName();  		}    		[Obsolete("方法以過時,請使用 CommonUtil.CopyText(text);")]  		public static void CopyText(string text)  		{  			CommonUtil.CopyText(text);  		}    		[Obsolete("方法以過時,請使用 EditorUtil.OpenInFolder(folderPath);")]  		public static void OpenInFolder(string folderPath)  		{  			EditorUtil.OpenInFolder(folderPath);  		}    #if UNITY_EDITOR  		[Obsolete("方法以過時,請使用 EditorUtil.CallMenuItem(menuPath);")]  		public static void CallMenuItem(string menuPath)  		{  			EditorUtil.CallMenuItem(menuPath);  		}    		[Obsolete("方法以過時,請使用 EditorUtil.ExportPackage(assetPathName, fileName);")]  		public static void ExportPackage(string assetPathName,string fileName)  		{  			EditorUtil.ExportPackage(assetPathName, fileName);  		}  #endif    #if UNITY_EDITOR  		[MenuItem("QFramework/8.總結之前的方法/1.獲取文件名")]  		private static void MenuClicked()  		{  			Debug.Log(Exporter.GenerateUnityPackageName());  		}    		[MenuItem("QFramework/8.總結之前的方法/2.複製文本到剪切板")]  		private static void MenuClicked2()  		{  			CommonUtil.CopyText("要複製的關鍵字");  		}    		[MenuItem("QFramework/8.總結之前的方法/3.生成文件名到剪切板")]  		private static void MenuClicked3()  		{  			CommonUtil.CopyText(GenerateUnityPackageName());  		}    		[MenuItem("QFramework/8.總結之前的方法/4.導出 UnityPackage")]  		private static void MenuClicked4()  		{  			EditorUtil.ExportPackage("Assets/QFramework",GenerateUnityPackageName() + ".unitypackage");  		}    		[MenuItem("QFramework/8.總結之前的方法/5.打開所在文件夾")]  		private static void MenuClicked5()  		{  			EditorUtil.OpenInFolder(Application.dataPath);  		}    		[MenuItem("QFramework/8.總結之前的方法/6.MenuItem 復用")]  		private static void MenuClicked6()  		{  			EditorUtil.CallMenuItem("QFramework/8.總結之前的方法/4.導出 UnityPackage");  			EditorUtil.OpenInFolder(Path.Combine(Application.dataPath, "../"));  		}  #endif  	}   }  

大家發現 PreviousFunctions 這個類里的所有的 MenuItem 方法里的實現,都改成了新的方法。

而筆者刪除了以下方法,原因是知識點和第七個示例重複了,有了第七個示例就不需要這個方法了。

		[MenuItem("QFramework/8.總結之前的方法/7.自定義快捷鍵")]  		private static void MenuClicked7()  		{  			Debug.Log("%e 意思是快捷鍵 cmd/ctrl + e");  		}  

小結

  1. 要做的事情:
    • (完成) 備份:導出文件,並取一個合理的名字。
  2. 遺留問題:
    • (完成一部分) 第八個示例與之前的示例程式碼重複,功能重複。
    • (完成) 方法所在類的命名有問題。
    • 菜單欄顯示順序問題。
  3. 約定和規則:
    • 每個示例在 QFramework 目錄下創建一個文件夾,文件夾的格式是: 數字.示例的功能
    • 每個示例寫一個腳本,腳本中包含可復用的靜態方法和 MenuItem 方法。
    • 每寫一個示例進行一次導出,導出的文件名後邊加上日期和時間,這個功能已經在導出功能里內置了。
    • 每次有 API 變更的時候做一次備份,備份的名字採用 QFramework_vX.Y.Z 格式。
    • 每次進行整理的時候要確保是在功能有效的情況下進行刪除和變更。
  4. 示例分類:
    1. 知識學習&收集
      • API 收集
      • C# 語法實踐
    2. 庫本身的功能
      • 規則實現
      • 使用流程提供及優化
      • 效率提升(編碼體驗、邏輯復用)
      • 項目實用工具收集

今天的內容就寫到這裡,下一篇再見,拜拜~

轉載請註明地址:涼鞋的筆記:liangxiegame.com

更多內容