C#模板生成

簡要說明

 創建代碼有多種方式。最簡單的,就按編輯器最初始的方法生成。稍微會點的就可以自己修改編輯器的模板。再深入一點的就可以自己定義一系列代碼模板,保存到文本文件,再讀出來,然後修改一些模板信息。用unity3d程序,我倒是習慣了在這程序中創建一個script而不是在vistual studio中去新建代碼。這樣的話,所有的代碼類型,如Interface,struct,enum都需要在創建出一個”不正確“的類後修改,修改是個重複的過程,這個過程必須去掉。

 而遺憾的是unity至今還是對所有的代碼一視同仁,連圖標都是用c#這麼“經典”的一個圖標。前一段時候,用過一些方法,無非是編寫一個代碼模板文檔,創建時,調用這些模板。最大的缺陷是太複雜,在不同的項目或電腦上都要靠一些不想要的模板文件。

 本文將使用Microsoft自己帶的代碼格式方案實現代碼的生成(因爲考慮到unity3d中暫不能很好的使用.net4.5,代碼解析的模塊還沒有開發)。

成果展示

 1.如果你喜歡簡單一點,直接點右鍵快速創建不同的類


2.當然,也有基本的配製窗口

 

 3.如果你需要創建一個不繼承於其他類的數據模型類,你可以這樣配製

 

 4.以上這個配製後,點擊create就可以生成代碼模板到指定的文件夾了

 

5.以下是一個接口,創建效果。此外你已經熟悉代碼規範了就可以在設置裏面取消顯示

 

技術要點

 1.將c#代碼單元生成字符串

  代碼也是一個個的文檔,官方都有文檔的格式,c#也不例外。這裏只是按格式寫,然後生成字符串,

需要說明的是c#並不能真的從string變成文檔結構,至少官方貌似沒有提供,但如果你可以使用net4.5以上的環境,

倒是可以研究下NRefactory

  using (Microsoft.CSharp.CSharpCodeProvider cprovider = new Microsoft.CSharp.CSharpCodeProvider())
            {
                StringBuilder fileContent = new StringBuilder();
                var option = new System.CodeDom.Compiler.CodeGeneratorOptions();
                option.BlankLinesBetweenMembers = false;
                using (StringWriter sw = new StringWriter(fileContent))
                {
                    cprovider.GenerateCodeFromNamespace(nameSpace, sw, option);
                }
                return fileContent.ToString();
            }

2.結合unity自己創建代碼的方式

因爲還沒有找到,unity3d當前打開的文件夾路徑,所以用了一個妥協的方案。就是先調用自帶的方法創建一個腳本,

然後去修改裏面的字符串(如果你找到了,不防提醒了一下)

        internal static void QuickCreateTemplate<T>() where T : ScriptTemplate, new()
        {
            EditorApplication.ExecuteMenuItem("Assets/Create/C# Script");
            EditorApplication.update = () =>
            {
                if (Selection.activeObject)
                {
                    var path = AssetDatabase.GetAssetPath(Selection.activeObject);
                    var temp = new T();
                    temp.headerInfo.scriptName = Path.GetFileNameWithoutExtension(path);
                    var dir = Path.GetDirectoryName(path);
                    var scr = temp.CreateScript();
                    temp.SaveToFile(dir, scr);
                    EditorApplication.update = null;
                }
            };
        }
 3.窗體緩存

因爲,將窗體的信息保存到本地文件,但又想要緩存一點信息,所以用了EditorPrefs和PlayerPrefs,

前面用來保存跨工程的用戶信息和窗體信息,後面用來保存當前程序的信息。即使這樣,因爲要緩存模板抽象類的信息,

還用到了類型記錄的一些方案

        public static TempScriptWindow GetWindow()
        {
            var window = EditorWindow.GetWindow<TempScriptWindow>();
            if (EditorPrefs.HasKey(prefer_key))
            {
                var json = EditorPrefs.GetString(prefer_window);
                JsonUtility.FromJsonOverwrite(json, window);
                window.LoadOldTemplates();
                return window;
            }
            return window;
        }
 
  internal static ScriptTemplate LoadFromJson(ScriptTemplate old)
        {
            if (!string.IsNullOrEmpty(old.type) && old.GetType().FullName != old.type)
            {
                var type = Type.GetType(old.type);
                if(type != null)
                {
                    var temp = Activator.CreateInstance(type);
                    JsonUtility.FromJsonOverwrite(old.json, temp);
                    return temp as ScriptTemplate;
                }
                else
                {
                    return old;
                }
            }
            else
            {
                old.type = old.GetType().FullName;
                return old;
            }
        }
 4.unity3d自帶列表ReorderableList

 以前沒發現這個類,所以用了其他的插件來寫列表。以上你看到的列表效果就是這樣寫的

        protected void InitDetailList()
        {
            detailList = new ReorderableList(headerInfo.detailInfo, typeof(string), true, false, true, true);
            detailList.onAddCallback += (x) => { headerInfo.detailInfo.Add(""); };
            detailList.drawHeaderCallback = (x) => { EditorGUI.LabelField(x, "詳細信息"); };
            detailList.drawElementCallback += (x, y, z, w) => { headerInfo.detailInfo[y] = EditorGUI.TextField(x, headerInfo.detailInfo[y]); };
        }


源碼分享

 爲了方便拷貝使用,我直接在一個腳本中寫了這些功能。雖然用了面對象的基本思路,但實際上在個文檔中寫,實在是難過,以後也儘量不要這樣幹。主要的是這個代碼後面應該還會更新,如果喜歡,或者有建議可以到我github中去找:https://github.com/zouhunter/Editor_Extends/blob/master/Core/Editor/TempScriptWindow.cs

#region statement
/************************************************************************************* 
    * 作    者:       zouhunter
    * 時    間:       2018-02-02 
    * 詳    細:       1.支持枚舉、模型、結構和繼承等類的模板。
                       2.支持快速創建通用型UI界面腳本
                       3.支持自定義模板類
                       4.自動生成作者、創建時間、描述等功能
                       5.支持工程同步(EditorPrefer)
   *************************************************************************************/
#endregion

using System;
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using UnityEditorInternal;
using System.CodeDom;
using System.IO;
using System.Text;
using NUnit.Framework.Constraints;
using NUnit.Framework;

namespace EditorTools
{
    #region Window
    /// <summary>
    /// 一個創建腳本模板的窗口
    /// </summary>
    public class TempScriptWindow : EditorWindow
    {
        [MenuItem("Window/TempScriptWindow")]
        static void Open()
        {
            var window = TempScriptHelper.GetWindow();
            window.wantsMouseMove = true;
        }


        [SerializeField]
        private List<ScriptTemplate> templates;
        ScriptTemplate currentTemplates { get { if (templates != null && templates.Count > currentIndex) return templates[currentIndex]; return null; } }
        private MonoScript script;
        [SerializeField]
        private bool isSetting;
        [SerializeField]
        private string authorName;
        [SerializeField]
        private string[] templateNames;
        [SerializeField]
        private int currentIndex;
        private Vector2 scrollPos;
        [SerializeField]
        private string[] templateType;
        private bool showRule;
        private string codeRule;
        private void OnEnable()
        {
            InitEnviroment();
        }

        private void OnDisable()
        {
            if (templates != null)
            {
                foreach (var item in templates)
                {

                    item.SaveToJson();
                }
            }
            EditorUtility.SetDirty(this);
            TempScriptHelper.SaveWindow(this);
        }
        private void OnGUI()
        {
            DrawHead();
            if (isSetting)
            {
                //繪製設置信息
                DrawSettings();
            }
            else
            {
                if (templates == null)
                {
                    Debug.Log("template == null");
                    templates = new List<ScriptTemplate>();
                }

                if (templates.Count == 0)
                {
                    Debug.Log("AddTemplates");
                    AddTemplates();
                }

                currentIndex = GUILayout.Toolbar(currentIndex, templateNames);
                using (var scroll = new EditorGUILayout.ScrollViewScope(scrollPos))
                {
                    scrollPos = scroll.scrollPosition;

                    if (currentTemplates != null)
                    {
                        if (currentTemplates.GetType().FullName != currentTemplates.type)
                        {
                            templates[currentIndex] = TempScriptHelper.LoadFromJson(currentTemplates);
                        }

                        currentTemplates.OnBodyGUI();

                        if (currentTemplates.GetType().FullName == typeof(ScriptTemplate).FullName)
                        {
                            if (templateType.Length > currentIndex)
                            {
                                var type = Type.GetType(templateType[currentIndex]);
                                if(type != null)
                                {
                                    templates[currentIndex] = Activator.CreateInstance(type) as ScriptTemplate;
                                    Debug.Log("create new:" + currentTemplates.GetType());
                                }
                                else
                                {
                                    Debug.LogFormat("{0} missing: clear templates", currentTemplates.GetType().FullName);
                                    templates.Clear();
                                }
                              
                            }
                            else
                            {
                                Debug.Log("unknow err: clear templates");
                                templates.Clear();
                            }
                        }
                    }
                    else
                    {
                        templates.Clear();
                        Debug.Log("templates.Count <= currentIndex");
                    }
                }
                if (currentTemplates != null)
                {
                    currentTemplates.OnFootGUI();
                }

            }

        }


        private void InitEnviroment()
        {
            if (script == null) script = MonoScript.FromScriptableObject(this);
            showRule = TempScriptHelper.GetRuleShowState();
            if (string.IsNullOrEmpty(codeRule)) codeRule = TempScriptHelper.GetCodeRule();
            if (string.IsNullOrEmpty(authorName)) authorName = TempScriptHelper.GetAuthor();
            if (string.IsNullOrEmpty(authorName))
            {
                isSetting = true;
            }
        }

        private void AddTemplates()
        {
            var assemble = this.GetType().Assembly;
            var allTypes = assemble.GetTypes();
            foreach (var item in allTypes)
            {
                if (item.IsSubclassOf(typeof(ScriptTemplate)))
                {
                    var template = Activator.CreateInstance(item);
                    templates.Add(template as ScriptTemplate);
                }
            }

            foreach (var item in templates)
            {
                item.OnEnable();
            }
            templateNames = templates.ConvertAll<string>(x => x.Name).ToArray();
            templateType = templates.ConvertAll<string>(x => x.GetType().FullName).ToArray();
        }

        public void LoadOldTemplates()
        {
            for (int i = 0; i < templates.Count; i++)
            {
                if (templates[i] == null)
                {
                    templates = null;
                    return;
                }

                var newitem = TempScriptHelper.LoadFromJson(templates[i]);

                if (newitem == null)
                {
                    templates = null;
                    return;
                }
                templates[i] = newitem;
            }
            templateNames = templates.ConvertAll<string>(x => x.Name).ToArray();
            templateType = templates.ConvertAll<string>(x => x.GetType().FullName).ToArray();
        }

        private void DrawHead()
        {
            using (var hor = new EditorGUILayout.HorizontalScope())
            {
                EditorGUILayout.ObjectField(script, typeof(MonoScript), false);
                if (!isSetting && GUILayout.Button("setting", EditorStyles.miniButtonRight, GUILayout.Width(60)))
                {
                    isSetting = true;
                }
                else if (isSetting && GUILayout.Button("confer", EditorStyles.miniButtonRight, GUILayout.Width(60)) && !string.IsNullOrEmpty(authorName))
                {
                    isSetting = false;
                }
            }

            if (!isSetting && GUILayout.Button("Clear", EditorStyles.toolbarButton))
            {
                if (currentTemplates != null)
                    currentTemplates.headerInfo = new TempScriptHeader() ;
                templates.Clear();
            }
        }

        private void DrawSettings()
        {
            using (var hor = new EditorGUILayout.HorizontalScope())
            {
                EditorGUI.BeginChangeCheck();
                EditorGUILayout.SelectableLabel("作者:", EditorStyles.miniLabel, GUILayout.Width(60));
                authorName = EditorGUILayout.TextField(authorName);
                if (EditorGUI.EndChangeCheck())
                {
                    if (!string.IsNullOrEmpty(authorName))
                    {
                        TempScriptHelper.SaveAuthor(authorName);
                    }
                }
            }
            EditorGUI.BeginChangeCheck();
            showRule = EditorGUILayout.ToggleLeft("在生成的代碼末尾顯示規範:(熟悉後可關閉此功能)", showRule);
            if (EditorGUI.EndChangeCheck())
            {
                TempScriptHelper.SetRuleShowState(showRule);
            }

            if (showRule)
            {
                using (var scrop = new EditorGUILayout.ScrollViewScope(scrollPos))
                {
                    scrollPos = scrop.scrollPosition;
                    EditorGUILayout.TextArea(codeRule);
                }
            }
        }


    }
    #endregion

    #region Tools
    /// <summary>
    /// 任何腳本的頭
    /// </summary>
    [System.Serializable]
    public class TempScriptHeader
    {
        public string author;
        public string time;
        public string description;
        public List<string> detailInfo = new List<string>();
        public string scriptName;
        public string nameSpace;

        public void Update()
        {
            author = TempScriptHelper.GetAuthor();
            time = System.DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
        }
    }

    /// <summary>
    /// 靜態工具類
    /// </summary>
    public static class TempScriptHelper
    {
        private const string prefer_key = "temp_script_autor_name";
        private const string prefer_window = "temp_script_window";
        private const string code_rule_show = "temp_script_code_rule_show";

        public static void SaveAuthor(string author)
        {
            EditorPrefs.SetString(prefer_key, author);
        }

        public static string GetAuthor()
        {
            return EditorPrefs.GetString(prefer_key);
        }

        public static void SaveWindow(TempScriptWindow window)
        {
            var json = JsonUtility.ToJson(window);
            EditorPrefs.SetString(prefer_window, json);
        }
        public static TempScriptWindow GetWindow()
        {
            var window = EditorWindow.GetWindow<TempScriptWindow>();
            if (EditorPrefs.HasKey(prefer_key))
            {
                var json = EditorPrefs.GetString(prefer_window);
                JsonUtility.FromJsonOverwrite(json, window);
                window.LoadOldTemplates();
                return window;
            }
            return window;
        }
        internal static ScriptTemplate LoadFromJson(ScriptTemplate old)
        {
            if (!string.IsNullOrEmpty(old.type) && old.GetType().FullName != old.type)
            {
                var type = Type.GetType(old.type);
                if(type != null)
                {
                    var temp = Activator.CreateInstance(type);
                    JsonUtility.FromJsonOverwrite(old.json, temp);
                    return temp as ScriptTemplate;
                }
                else
                {
                    return old;
                }
            }
            else
            {
                old.type = old.GetType().FullName;
                return old;
            }
        }

        internal static void SetRuleShowState(bool enabled)
        {
            PlayerPrefs.SetInt(code_rule_show, enabled ? 1 : 0);
        }
        internal static bool GetRuleShowState()
        {
            if (PlayerPrefs.HasKey(code_rule_show))
            {
                return PlayerPrefs.GetInt(code_rule_show) == 1;
            }
            return true;
        }
        /*
         1.私有字段:_field,m_field
         2.公有字段:field
         2.屬性:Property
         3.常量:CONST
         4.靜態變量:Field,Property
             */
        internal static string GetCodeRule()
        {
            return @"#region 代碼規範
/*************************************************************************************
        【變量命名】:
         1.私有字段:_field,m_field
         2.公有字段:field
         2.屬性:Property
         3.常量:CONST
         4.靜態變量:Field,Property
**************************************************************************************/
#endregion
";
        }

        internal static void QuickCreateTemplate<T>() where T : ScriptTemplate, new()
        {
            EditorApplication.ExecuteMenuItem("Assets/Create/C# Script");
            EditorApplication.update = () =>
            {
                if (Selection.activeObject)
                {
                    var path = AssetDatabase.GetAssetPath(Selection.activeObject);
                    var temp = new T();
                    temp.headerInfo.scriptName = Path.GetFileNameWithoutExtension(path);
                    var dir = Path.GetDirectoryName(path);
                    var scr = temp.CreateScript();
                    temp.SaveToFile(dir, scr);
                    EditorApplication.update = null;
                }
            };
        }
    }
    #endregion

    #region Templates
    /// <summary>
    /// 代碼創建模板的模板
    /// </summary>
    [System.Serializable]
    public class ScriptTemplate
    {
        [System.Serializable]
        public class FieldItem
        {
            public string type;
            public string elementName;
            public string comment;
        }
        [System.Serializable]
        public class PropertyItem
        {
            public string type;
            public string elementName;
            public string comment;
            public bool get;
            public bool set;
            public PropertyItem()
            {
                get = set = true;
            }
        }
        [SerializeField]
        protected List<FieldItem> fields = new List<FieldItem>();
        [SerializeField]
        protected List<PropertyItem> propertys = new List<PropertyItem>();

        public string json;
        public string type;
        public TempScriptHeader headerInfo = new TempScriptHeader();
        public string path;
        public virtual string Name { get { return null; } }
        private ReorderableList detailList;

        public virtual void OnBodyGUI() { }
        public virtual void OnFootGUI()
        {
            if (detailList == null)
            {
                InitDetailList();
            }

            if (detailList.list != headerInfo.detailInfo)
            {
                detailList.list = headerInfo.detailInfo;
            }

            using (var horm = new EditorGUILayout.HorizontalScope())
            {
                EditorGUILayout.LabelField("Namespace", GUILayout.Width(70));
                headerInfo.nameSpace = EditorGUILayout.TextField(headerInfo.nameSpace, GUILayout.Width(60));
                EditorGUILayout.LabelField("Type", GUILayout.Width(40));
                headerInfo.scriptName = EditorGUILayout.TextField(headerInfo.scriptName, GUILayout.Width(60));
                EditorGUILayout.LabelField("簡介", GUILayout.Width(40));
                headerInfo.description = EditorGUILayout.TextField(headerInfo.description);

                if (GUILayout.Button("Load", EditorStyles.miniButtonRight, GUILayout.Width(60)))
                {
                    OnLoadButtonClicked();
                }
            }
            using (var hor = new EditorGUILayout.HorizontalScope())
            {
                using (var vertical = new EditorGUILayout.VerticalScope())
                {
                    detailList.DoLayoutList();
                }
                using (var vertical = new EditorGUILayout.VerticalScope(GUILayout.Width(60)))
                {
                    if (GUILayout.Button("Create", EditorStyles.miniButtonRight, GUILayout.Height(60)))
                    {
                        OnCreateButtonClicked();
                    }
                }
            }
        }

        public void OnEnable()
        {
            type = this.GetType().FullName;
            Debug.Log(type);
        }

        public string CreateScript()
        {
            var ns = CreateNameSpace();
            if (ns == null) return null;
            var nsstr = ComplieNameSpaceToString(ns);
            if (string.IsNullOrEmpty(nsstr)) return null;

            var scriptStr = GetHeader() + nsstr + GetFooter();

            if (string.IsNullOrEmpty(scriptStr))
            {
                EditorUtility.DisplayDialog("生成失敗", "請看日誌!", "確認");
                return null;
            }

            return scriptStr;


        }
        public void SaveToJson()
        {
            json = null;
            json = JsonUtility.ToJson(this);
            if (string.IsNullOrEmpty(type))
            {
                type = this.GetType().FullName;
            }
        }
        protected void InitDetailList()
        {
            detailList = new ReorderableList(headerInfo.detailInfo, typeof(string), true, false, true, true);
            detailList.onAddCallback += (x) => { headerInfo.detailInfo.Add(""); };
            detailList.drawHeaderCallback = (x) => { EditorGUI.LabelField(x, "詳細信息"); };
            detailList.drawElementCallback += (x, y, z, w) => { headerInfo.detailInfo[y] = EditorGUI.TextField(x, headerInfo.detailInfo[y]); };
        }

        protected void DrawFieldItem(Rect rect, FieldItem dataItem, bool haveType)
        {
            if (haveType)
            {
                var rect01 = new Rect(rect.x, rect.y, rect.width * 0.2f, EditorGUIUtility.singleLineHeight);
                var typeRect = new Rect(rect.x + 0.2f * rect.width, rect.y, rect.width * 0.1f, EditorGUIUtility.singleLineHeight);
                var rect02 = new Rect(rect.x + rect.width * 0.3f, rect.y, rect.width * 0.3f, EditorGUIUtility.singleLineHeight);
                var commentRect = new Rect(rect.x + 0.6f * rect.width, rect.y, rect.width * 0.1f, EditorGUIUtility.singleLineHeight);
                var rect03 = new Rect(rect.x + rect.width * 0.7f, rect.y, rect.width * 0.3f, EditorGUIUtility.singleLineHeight);

                dataItem.elementName = EditorGUI.TextField(rect01, dataItem.elementName);
                EditorGUI.LabelField(typeRect, "Type");
                dataItem.type = EditorGUI.TextField(rect02, dataItem.type);
                EditorGUI.LabelField(commentRect, "Comment");
                dataItem.comment = EditorGUI.TextField(rect03, dataItem.comment);
            }
            else
            {
                var left = new Rect(rect.x, rect.y, rect.width * 0.3f, EditorGUIUtility.singleLineHeight);
                var right = new Rect(rect.x + rect.width * 0.4f, rect.y, rect.width * 0.6f, EditorGUIUtility.singleLineHeight);
                var center = new Rect(rect.x + rect.width * 0.3f, rect.y, rect.width * 0.1f, EditorGUIUtility.singleLineHeight);
                dataItem.elementName = EditorGUI.TextField(left, dataItem.elementName);
                EditorGUI.LabelField(center, "Comment");
                dataItem.comment = EditorGUI.TextField(right, dataItem.comment);
            }

        }
        protected void DrawPropertyItem(Rect rect, PropertyItem propertyItem)
        {
            var rect01 = new Rect(rect.x, rect.y, rect.width * 0.2f, EditorGUIUtility.singleLineHeight);
            var typeRect = new Rect(rect.x + 0.2f * rect.width, rect.y, rect.width * 0.1f, EditorGUIUtility.singleLineHeight);
            var rect02 = new Rect(rect.x + rect.width * 0.3f, rect.y, rect.width * 0.3f, EditorGUIUtility.singleLineHeight);
            var commentRect = new Rect(rect.x + 0.6f * rect.width, rect.y, rect.width * 0.1f, EditorGUIUtility.singleLineHeight);
            var rect03 = new Rect(rect.x + rect.width * 0.7f, rect.y, rect.width * 0.3f, EditorGUIUtility.singleLineHeight);

            propertyItem.elementName = EditorGUI.TextField(rect01, propertyItem.elementName);
            EditorGUI.LabelField(typeRect, "Type");
            propertyItem.type = EditorGUI.TextField(rect02, propertyItem.type);
            EditorGUI.LabelField(commentRect, "Comment");
            propertyItem.comment = EditorGUI.TextField(rect03, propertyItem.comment);

            var getLabelRect = new Rect(rect.x, rect.y + EditorGUIUtility.singleLineHeight, rect.width * 0.1f, EditorGUIUtility.singleLineHeight);
            var getRect = new Rect(rect.x + 0.1f * rect.width, rect.y + EditorGUIUtility.singleLineHeight, rect.width * 0.1f, EditorGUIUtility.singleLineHeight);
            var setLabelRect = new Rect(rect.x + 0.2f * rect.width, rect.y + EditorGUIUtility.singleLineHeight, rect.width * 0.1f, EditorGUIUtility.singleLineHeight);
            var setRect = new Rect(rect.x + 0.3f * rect.width, rect.y + EditorGUIUtility.singleLineHeight, rect.width * 0.1f, EditorGUIUtility.singleLineHeight);

            EditorGUI.LabelField(getLabelRect, "get");
            propertyItem.get = EditorGUI.Toggle(getRect, propertyItem.get);
            EditorGUI.LabelField(setLabelRect, "set");
            propertyItem.set = EditorGUI.Toggle(setRect, propertyItem.set);

        }

        protected virtual CodeNamespace CreateNameSpace()
        {
            return null;
        }
        protected string GetHeader()
        {
            headerInfo.Update();

            var str1 = "#region statement\r\n" +
            "/*************************************************************************************   \r\n" +
            "    * 作    者:       {0}\r\n" +
            "    * 時    間:       {1}\r\n" +
            "    * 說    明:       ";
            var str2 = "\r\n                       ";
            var str3 = "\r\n* ************************************************************************************/" +
            "\r\n#endregion\r\n";

            var headerStr = string.Format(str1, headerInfo.author, headerInfo.time);
            for (int i = 0; i < headerInfo.detailInfo.Count; i++)
            {
                if (i == 0)
                {
                    headerStr += string.Format("{0}.{1}", i + 1, headerInfo.detailInfo[i]);
                }
                else
                {
                    headerStr += string.Format("{0}{1}.{2}", str2, i + 1, headerInfo.detailInfo[i]);
                }
            }
            headerStr += str3;
            return headerStr;
        }
        protected string ComplieNameSpaceToString(CodeNamespace nameSpace)
        {
            using (Microsoft.CSharp.CSharpCodeProvider cprovider = new Microsoft.CSharp.CSharpCodeProvider())
            {
                StringBuilder fileContent = new StringBuilder();
                var option = new System.CodeDom.Compiler.CodeGeneratorOptions();
                option.BlankLinesBetweenMembers = false;
                using (StringWriter sw = new StringWriter(fileContent))
                {
                    cprovider.GenerateCodeFromNamespace(nameSpace, sw, option);
                }
                return fileContent.ToString();
            }
        }
        protected string GetFooter()
        {
            if (TempScriptHelper.GetRuleShowState())
            {
                var rule = TempScriptHelper.GetCodeRule();
                return rule;
            }
            return null;
        }
        /// <summary>
        /// 點擊創建
        /// </summary>
        private void OnCreateButtonClicked()
        {
            if (string.IsNullOrEmpty(headerInfo.scriptName))
            {
                EditorUtility.DisplayDialog("腳本名爲空", "請填寫代碼名稱!", "確認");
                return;
            }


            if (string.IsNullOrEmpty(path))
            {
                if (ProjectWindowUtil.IsFolder(Selection.activeInstanceID))
                {
                    path = AssetDatabase.GetAssetPath(Selection.activeInstanceID);
                }
                else if (Selection.activeObject != null)
                {
                    var assetPath = AssetDatabase.GetAssetPath(Selection.activeObject);
                    if (!string.IsNullOrEmpty(assetPath))
                    {
                        path = assetPath.Replace(System.IO.Path.GetFileName(assetPath), "");
                    }
                }
            }
            var scriptStr = CreateScript();
            if (!string.IsNullOrEmpty(scriptStr))
            {
                SaveToFile(path, scriptStr);
            }

        }
        /// <summary>
        /// 保存到文件
        /// </summary>
        /// <param name="path"></param>
        /// <param name="scriptStr"></param>
        public void SaveToFile(string path, string scriptStr)
        {
            if (!string.IsNullOrEmpty(path))
            {
                var scriptPath = string.Format("{0}/{1}.cs", path, headerInfo.scriptName);
                System.IO.File.WriteAllText(scriptPath, scriptStr, System.Text.Encoding.UTF8);
                AssetDatabase.Refresh();
            }
            else
            {
                EditorUtility.DisplayDialog("路徑不明", "請選中文件夾後重試", "確認");
            }

        }

        /// <summary>
        /// 點擊加載代碼
        /// </summary>
        private void OnLoadButtonClicked()
        {
            if (!(Selection.activeObject is TextAsset))
            {
                EditorUtility.DisplayDialog("未選中", "請選中需要解析的代碼後繼續", "確認");
                return;
            }

            var path = AssetDatabase.GetAssetPath(Selection.activeObject);
            if (!path.EndsWith(".cs"))
            {
                EditorUtility.DisplayDialog("未選中", "請選中需要解析的代碼後繼續", "確認");
                return;
            }

            using (var provider = System.CodeDom.Compiler.CodeDomProvider.CreateProvider("CSharp"))
            {
                EditorUtility.DisplayDialog("未開發", ".net 3.5暫無該實現", "確認");

                var fileContent = System.IO.File.ReadAllText(path, Encoding.UTF8);
                using (StringReader sr = new StringReader(fileContent))
                {
                    var nameSpaceUnit = provider.Parse(sr);
                    Debug.Log(nameSpaceUnit);
                }
            }
        }
    }
    #endregion

    #region Enum
    /// <summary>
    /// 1.枚舉類型腳本
    /// </summary>
    [Serializable]
    public class EnumScriptTemplate : ScriptTemplate
    {
        [MenuItem("Assets/Create/C# TempScripts/Enum", priority = 5)]
        static void CreateEnum()
        {
            TempScriptHelper.QuickCreateTemplate<EnumScriptTemplate>();
        }

        public override string Name
        {
            get
            {
                return "Enum";
            }
        }

        private ReorderableList reorderableList;

        public EnumScriptTemplate()
        {
            reorderableList = new ReorderableList(fields, typeof(string));
            reorderableList.onAddCallback += (x) => { fields.Add(new FieldItem()); };
            reorderableList.drawHeaderCallback += (x) => { EditorGUI.LabelField(x, "枚舉列表"); };
            reorderableList.drawElementCallback += (x, y, z, w) =>
            {
                DrawFieldItem(x, fields[y], false);
            };
        }

        protected override CodeNamespace CreateNameSpace()
        {
            List<CodeMemberField> fields = new List<CodeMemberField>();
            foreach (var item in base.fields)
            {
                CodeMemberField prop = new CodeMemberField();
                prop.Name = item.elementName;
                prop.Comments.Add(new CodeCommentStatement(item.comment));
                fields.Add(prop);
            }

            CodeTypeDeclaration wrapProxyClass = new CodeTypeDeclaration(headerInfo.scriptName);
            wrapProxyClass.TypeAttributes = System.Reflection.TypeAttributes.Public;
            wrapProxyClass.IsEnum = true;

            wrapProxyClass.Comments.Add(new CodeCommentStatement("<summary>", true));
            wrapProxyClass.Comments.Add(new CodeCommentStatement(headerInfo.description, true));
            wrapProxyClass.Comments.Add(new CodeCommentStatement("<summary>", true));
            foreach (var field in fields)
            {
                wrapProxyClass.Members.Add(field);
            }

            CodeNamespace nameSpace = new CodeNamespace(headerInfo.nameSpace);
            nameSpace.Types.Add(wrapProxyClass);
            return nameSpace;
        }
        public override void OnBodyGUI()
        {
            reorderableList.DoLayoutList();
        }
    }
    #endregion

    #region DataModel
    /// <summary>
    /// 2.數據模擬類
    /// </summary>
    [Serializable]
    public class DataModelTemplate : ScriptTemplate
    {
        [MenuItem("Assets/Create/C# TempScripts/Model", priority = 5)]
        static void CreateModel()
        {
            TempScriptHelper.QuickCreateTemplate<DataModelTemplate>();
        }
        public override string Name
        {
            get
            {
                return "Model";
            }
        }

        [SerializeField]
        private List<string> imports = new List<string>() {
            "System",
            "UnityEngine",
            "UnityEngine.UI",
            "System.Collections",
            "System.Collections.Generic",
        };
        private ReorderableList nameSpaceList;
        private ReorderableList reorderableList;

        public DataModelTemplate()
        {
            reorderableList = new ReorderableList(fields, typeof(string));
            reorderableList.onAddCallback += (x) => { fields.Add(new FieldItem()); };
            reorderableList.drawHeaderCallback += (x) => { EditorGUI.LabelField(x, "模型名"); };
            reorderableList.drawElementCallback += (x, y, z, w) =>
            {
                DrawFieldItem(x, fields[y], true);
            };

            nameSpaceList = new ReorderableList(imports, typeof(string));
            nameSpaceList.onAddCallback += (x) => { imports.Add(""); };
            nameSpaceList.drawHeaderCallback += (x) => { EditorGUI.LabelField(x, "命名空間"); };
            nameSpaceList.drawElementCallback += (x, y, z, w) =>
            {
                imports[y] = DrawNameSpace(x, imports[y]);
            };
        }

        protected override CodeNamespace CreateNameSpace()
        {
            List<CodeMemberField> fields = new List<CodeMemberField>();
            foreach (var item in base.fields)
            {
                CodeMemberField prop = new CodeMemberField();
                prop.Type = new CodeTypeReference(item.type, CodeTypeReferenceOptions.GenericTypeParameter);
                prop.Attributes = MemberAttributes.Public;
                prop.Name = item.elementName;
                prop.Comments.Add(new CodeCommentStatement(item.comment));
                fields.Add(prop);
            }

            CodeTypeDeclaration wrapProxyClass = new CodeTypeDeclaration(headerInfo.scriptName);
            wrapProxyClass.TypeAttributes = System.Reflection.TypeAttributes.Public;
            wrapProxyClass.CustomAttributes.Add(new CodeAttributeDeclaration(typeof(System.SerializableAttribute).FullName));
            wrapProxyClass.IsClass = true;
            var destription = string.IsNullOrEmpty(headerInfo.description) ? "數據模型" : headerInfo.description;
            wrapProxyClass.Comments.Add(new CodeCommentStatement("<summary>", true));
            wrapProxyClass.Comments.Add(new CodeCommentStatement(destription, true));
            wrapProxyClass.Comments.Add(new CodeCommentStatement("<summary>", true));
            foreach (var field in fields)
            {
                wrapProxyClass.Members.Add(field);
            }
            CodeNamespace nameSpace = new CodeNamespace(headerInfo.nameSpace);
            nameSpace.Types.Add(wrapProxyClass);
            nameSpace.Imports.AddRange(imports.ConvertAll<CodeNamespaceImport>(x => new CodeNamespaceImport(x)).ToArray());
            return nameSpace;
        }


        private string DrawNameSpace(Rect rect, string dataItem)
        {
            var rect1 = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight);
            return EditorGUI.TextField(rect1, dataItem);
        }

        public override void OnBodyGUI()
        {
            nameSpaceList.DoLayoutList();
            reorderableList.DoLayoutList();
        }
    }
    #endregion

    #region Static
    /// <summary>
    /// 3.靜態類
    /// </summary>
    [Serializable]
    public class StaticClassTemplate : ScriptTemplate
    {
        [MenuItem("Assets/Create/C# TempScripts/Static", priority = 5)]
        static void CreateModel()
        {
            TempScriptHelper.QuickCreateTemplate<StaticClassTemplate>();
        }
        public override string Name
        {
            get
            {
                return "Static";
            }
        }

        [SerializeField]
        private List<string> imports = new List<string>() {
            "System",
            "UnityEngine"
        };
        private ReorderableList nameSpaceList;
        private ReorderableList propertyList;
        private ReorderableList fieldList;

        public StaticClassTemplate()
        {
            fieldList = new ReorderableList(fields, typeof(string));
            fieldList.onAddCallback += (x) => { fields.Add(new FieldItem()); };
            fieldList.drawHeaderCallback += (x) => { EditorGUI.LabelField(x, "字段"); };
            fieldList.drawElementCallback += (x, y, z, w) =>
            {
                DrawFieldItem(x, fields[y], true);
            };

            propertyList = new ReorderableList(propertys, typeof(string));
            propertyList.onAddCallback += (x) => { propertys.Add(new PropertyItem()); };
            propertyList.drawHeaderCallback += (x) => { EditorGUI.LabelField(x, "屬性"); };
            propertyList.elementHeightCallback = (x) => { return 2 * EditorGUIUtility.singleLineHeight; };
            propertyList.drawElementCallback += (x, y, z, w) =>
            {
                DrawPropertyItem(x, propertys[y]);
            };

            nameSpaceList = new ReorderableList(imports, typeof(string));
            nameSpaceList.onAddCallback += (x) => { imports.Add(""); };
            nameSpaceList.drawHeaderCallback += (x) => { EditorGUI.LabelField(x, "命名空間"); };
            nameSpaceList.drawElementCallback += (x, y, z, w) =>
            {
                imports[y] = DrawNameSpace(x, imports[y]);
            };
        }


        protected override CodeNamespace CreateNameSpace()
        {
            List<CodeMemberField> codeFields = new List<CodeMemberField>();
            foreach (var item in fields)
            {
                CodeMemberField field = new CodeMemberField();
                field.Type = new CodeTypeReference(item.type, CodeTypeReferenceOptions.GenericTypeParameter);
                field.Attributes = MemberAttributes.Public | MemberAttributes.Static;
                field.Name = item.elementName;
                //field.InitExpression = invokeExpression;
                field.Comments.Add(new CodeCommentStatement(item.comment));
                codeFields.Add(field);
            }


            List<CodeMemberProperty> propertysMemper = new List<CodeMemberProperty>();
            foreach (var item in propertys)
            {
                CodeMemberProperty prop = new CodeMemberProperty();
                prop.Type = new CodeTypeReference(item.type, CodeTypeReferenceOptions.GenericTypeParameter);
                prop.Attributes = MemberAttributes.Public|MemberAttributes.Static;
                prop.Name = item.elementName;
                prop.HasGet = item.get;
                prop.HasSet = item.set;
                //CodeExpression invokeExpression = new CodePropertyReferenceExpression();
                prop.GetStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(null)));
                prop.Comments.Add(new CodeCommentStatement(item.comment));
                propertysMemper.Add(prop);
            }

            CodeTypeDeclaration wrapProxyClass = new CodeTypeDeclaration(headerInfo.scriptName);
            wrapProxyClass.TypeAttributes = System.Reflection.TypeAttributes.Public;//沒有靜態?
            wrapProxyClass.Attributes = MemberAttributes.Static;
            wrapProxyClass.IsClass = true;
            var destription = string.IsNullOrEmpty(headerInfo.description) ? "靜態類" : headerInfo.description;
            wrapProxyClass.Comments.Add(new CodeCommentStatement("<summary>", true));
            wrapProxyClass.Comments.Add(new CodeCommentStatement(destription, true));
            wrapProxyClass.Comments.Add(new CodeCommentStatement("<summary>", true));
            foreach (var prop in propertysMemper)
            {
                wrapProxyClass.Members.Add(prop);
            }
            foreach (var field in codeFields)
            {
                wrapProxyClass.Members.Add(field);
            }
            CodeNamespace nameSpace = new CodeNamespace(headerInfo.nameSpace);
            nameSpace.Types.Add(wrapProxyClass);
            nameSpace.Imports.AddRange(imports.ConvertAll<CodeNamespaceImport>(x => new CodeNamespaceImport(x)).ToArray());
            return nameSpace;
        }

        private string DrawNameSpace(Rect rect, string dataItem)
        {
            var rect1 = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight);
            return EditorGUI.TextField(rect1, dataItem);
        }

        public override void OnBodyGUI()
        {
            nameSpaceList.DoLayoutList();
            fieldList.DoLayoutList();
            propertyList.DoLayoutList();
        }
    }

    #endregion

    #region Struct
    /// <summary>
    /// 5.結構體模板
    /// </summary>
    [Serializable]
    public class StructTempate : ScriptTemplate
    {
        [MenuItem("Assets/Create/C# TempScripts/Struct", priority = 5)]
        static void CreateStruct()
        {
            TempScriptHelper.QuickCreateTemplate<StructTempate>();
        }

        public override string Name
        {
            get
            {
                return "Struct";
            }
        }

        [SerializeField]
        private List<string> imports = new List<string>() {
            "System",
            "UnityEngine",
            "UnityEngine.UI",
            "System.Collections",
            "System.Collections.Generic",
        };
        private ReorderableList nameSpaceList;
        private ReorderableList reorderableList;

        public StructTempate()
        {
            reorderableList = new ReorderableList(fields, typeof(string));
            reorderableList.onAddCallback += (x) => { fields.Add(new FieldItem()); };
            reorderableList.drawHeaderCallback += (x) => { EditorGUI.LabelField(x, "模型名"); };
            reorderableList.drawElementCallback += (x, y, z, w) =>
            {
                DrawFieldItem(x, fields[y], true);
            };

            nameSpaceList = new ReorderableList(imports, typeof(string));
            nameSpaceList.onAddCallback += (x) => { imports.Add(""); };
            nameSpaceList.drawHeaderCallback += (x) => { EditorGUI.LabelField(x, "命名空間"); };
            nameSpaceList.drawElementCallback += (x, y, z, w) =>
            {
                imports[y] = DrawNameSpace(x, imports[y]);
            };
        }

        protected override CodeNamespace CreateNameSpace()
        {
            List<CodeMemberField> fields = new List<CodeMemberField>();
            foreach (var item in base.fields)
            {
                CodeMemberField prop = new CodeMemberField();
                prop.Type = new CodeTypeReference(item.type, CodeTypeReferenceOptions.GenericTypeParameter);
                prop.Attributes = MemberAttributes.Public;
                prop.Name = item.elementName;
                prop.Comments.Add(new CodeCommentStatement(item.comment));
                fields.Add(prop);
            }

            CodeTypeDeclaration wrapProxyClass = new CodeTypeDeclaration(headerInfo.scriptName);
            wrapProxyClass.TypeAttributes = System.Reflection.TypeAttributes.Public;
            wrapProxyClass.IsStruct = true;
            var destription = string.IsNullOrEmpty(headerInfo.description) ? "結構體" : headerInfo.description;
            wrapProxyClass.Comments.Add(new CodeCommentStatement("<summary>", true));
            wrapProxyClass.Comments.Add(new CodeCommentStatement(destription, true));
            wrapProxyClass.Comments.Add(new CodeCommentStatement("<summary>", true));
            foreach (var field in fields)
            {
                wrapProxyClass.Members.Add(field);
            }
            CodeNamespace nameSpace = new CodeNamespace(headerInfo.nameSpace);
            nameSpace.Types.Add(wrapProxyClass);
            nameSpace.Imports.AddRange(imports.ConvertAll<CodeNamespaceImport>(x => new CodeNamespaceImport(x)).ToArray());
            return nameSpace;
        }

        private string DrawNameSpace(Rect rect, string dataItem)
        {
            var rect1 = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight);
            return EditorGUI.TextField(rect1, dataItem);
        }

        public override void OnBodyGUI()
        {
            nameSpaceList.DoLayoutList();
            reorderableList.DoLayoutList();
        }
    }
    #endregion

    #region Interface
    /// <summary>
    /// 6.接口創建模板
    /// </summary>
    [Serializable]
    public class InterfaceTempate : ScriptTemplate
    {
        [MenuItem("Assets/Create/C# TempScripts/Interface", priority = 5)]
        static void CreateEnum()
        {
            TempScriptHelper.QuickCreateTemplate<InterfaceTempate>();
        }

        public override string Name
        {
            get
            {
                return "Interface";
            }
        }

        [SerializeField]
        private List<string> imports = new List<string>() {
            "System",
            "UnityEngine"
        };
        private ReorderableList nameSpaceList;
        private ReorderableList reorderableList;

        public InterfaceTempate()
        {
            reorderableList = new ReorderableList(propertys, typeof(string));
            reorderableList.onAddCallback += (x) => { propertys.Add(new PropertyItem()); };
            reorderableList.drawHeaderCallback += (x) => { EditorGUI.LabelField(x, "屬性"); };
            reorderableList.elementHeightCallback = (x) => { return 2 * EditorGUIUtility.singleLineHeight; };
            reorderableList.drawElementCallback += (x, y, z, w) =>
            {
                DrawPropertyItem(x, propertys[y]);
            };

            nameSpaceList = new ReorderableList(imports, typeof(string));
            nameSpaceList.onAddCallback += (x) => { imports.Add(""); };
            nameSpaceList.drawHeaderCallback += (x) => { EditorGUI.LabelField(x, "命名空間"); };
            nameSpaceList.drawElementCallback += (x, y, z, w) =>
            {
                imports[y] = DrawNameSpace(x, imports[y]);
            };
        }


        protected override CodeNamespace CreateNameSpace()
        {
            List<CodeMemberProperty> propertysMemper = new List<CodeMemberProperty>();
            foreach (var item in propertys)
            {
                CodeMemberProperty prop = new CodeMemberProperty();
                prop.Type = new CodeTypeReference(item.type, CodeTypeReferenceOptions.GenericTypeParameter);
                prop.Attributes = MemberAttributes.Public;
                prop.Name = item.elementName;
                prop.HasGet = item.get;
                prop.HasSet = item.set;
                prop.Comments.Add(new CodeCommentStatement(item.comment));
                propertysMemper.Add(prop);
            }

            CodeTypeDeclaration wrapProxyClass = new CodeTypeDeclaration(headerInfo.scriptName);
            wrapProxyClass.TypeAttributes = System.Reflection.TypeAttributes.Public;
            wrapProxyClass.IsInterface = true;
            var destription = string.IsNullOrEmpty(headerInfo.description) ? "接口" : headerInfo.description;
            wrapProxyClass.Comments.Add(new CodeCommentStatement("<summary>", true));
            wrapProxyClass.Comments.Add(new CodeCommentStatement(destription, true));
            wrapProxyClass.Comments.Add(new CodeCommentStatement("<summary>", true));
            foreach (var prop in propertysMemper)
            {
                wrapProxyClass.Members.Add(prop);
            }
            CodeNamespace nameSpace = new CodeNamespace(headerInfo.nameSpace);
            nameSpace.Types.Add(wrapProxyClass);
            nameSpace.Imports.AddRange(imports.ConvertAll<CodeNamespaceImport>(x => new CodeNamespaceImport(x)).ToArray());
            return nameSpace;
        }

        private string DrawNameSpace(Rect rect, string dataItem)
        {
            var rect1 = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight);
            return EditorGUI.TextField(rect1, dataItem);
        }

        public override void OnBodyGUI()
        {
            nameSpaceList.DoLayoutList();
            reorderableList.DoLayoutList();
        }
    }
    #endregion


    ///下面可以自定義你的代碼生成模板
    ///...
    /// <summary>
    /// UI模板
    /// </summary>
    //[Serializable]
    //public class UIPanelTempate : ScriptTemplate
    //{
    //    public override string Name
    //    {
    //        get
    //        {
    //            return "UIPanel";
    //        }
    //    }

    //    protected override CodeNamespace CreateNameSpace()
    //    {
    //        return null;
    //    }

    //    public override void OnBodyGUI()
    //    {

    //    }
    //}

}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章