להתחבר לקומפיילר בקלות באמצעות Roslyn

5 באוקטובר 2014

אין תגובות

פרויקט Rosyln חושף את הקומפלייר באמצעות ממשק תכנות (API) קל לשימוש, מה שמאפשר לפתח יותר בקלות כלים המתממשקים למנגנונים הפנימיים של הקומפיילר כגון כלי אנליזה,ולידציה, refactoring וכו’. בפוסט הזה אני רוצה לספר איך באמצעות רוזלין אפשר בקלות להוסיף גמישות רבה לאפליקציה. לחסוך זמן בפיתוח, לבנות מערכות עם יכולת התאמה אישית ורכוש עוד לקוחות מרוצים!..

הכירו את Roslyn

עד עתה הקומפיילרים היו בגדר “קופסא שחורה” אשר עשתה את עבודתה מאחורי הקלעים: הקומפיילר מקבל לתוכו קוד מקור, מבצע את עבודתו המסתורית, ופולט קבצים מהודרים.

בפרוייקט Roslyn, מפתחי מיקרוסופט אשר אחראים על פיתוח כלי המפתחים כמו Visual Studio,  שיכתבו לחלוטין מחדש את מנוע הקומפיילר וחשפו ממשק תכנות (API) אשר מאפשר לגשת בקלות למה שמתרחש בקומפיילר מאחורי הקלעים. 

Roslyn – Compiler as a Service

באמצעות Roslyn ניתן לנתח קוד מקור, לשנות אותו, לבצע מניפולציות שונות וניתוחים שונים כו’. עד עתה פעולות מעין אלו היו מורכבות יחסית אך פרוייקט Roslyn נותן לנו דרך קלה לבצע זאת.

באמצעות שכתוב הקומפיילרים וחשיפת ממשק פשוט לשימוש, הקומפיילר החדש נחשף כשירות הנותן לנו מידע יקר ערך על הקוד, ונותן למפתחים אפשרות קלה לפתח כלי פיתוח עשירים יותר כמו refactoring tools, כלי ולידציה, visualizations ועוד דרכים שעוזרות לנו לפתח בצורה טובה, יעילה וקלה יותר.

דוגמאות למה שאפשר לעשות באמצעות Roslyn.

  • refactoring – כלי refactoring אינם צריכים עוד לנתח את הקוד המקורי ולהפיק ממנו את המידע מחדש. ניתן להשתמש באובייקטים ש-Roslyn מספקת לשם כך.
  • code analysis – ניתן לבצע אנליזה סטטית לקוד בקלות.
  • שיפורים בזמן אמת – ניתן לפתח למשל הרחבות ל- Visual Studio אשר בודקות שגיאות בזמן אמת וכו’.
  • C# Interactive window – כלי חדש חזק יותר מ- Immediate Window המאפשר לכם לנצל את כוחו המלא של Visual Studio בזמן שאתם כותבים קוד על ידי ניצול היתרונות ש- Roslyn מספקת לנו – ניתוח בזמן אמת של הקוד בצורה יעילה יותר.
  • אוטומציה – Roslyn חשפת כלי שורת פקודה חדש הנקרא rcsi.exe המאפשר לייצר סקריפטים בסיומת csx, שהם סקריפטים ב-#C לביצוע פעולות אוטומציה.

1

העובדה ש "רוזלין" היא קוד פתוח (Open Source), מאפשרת לקהילה התוססת של .NET להבין לעומק איך תהליך קומפילציה עובד, איך לשפר את חווית המפתח על ידי פיתוח תוספים ל-Visual Studio וחשוב ביותר היא מאפשרת לקחת חלק פעיל בכיוונים העתידים של פיתוח קומפיילרים ל-.NET. ולא רק להיות צופה מהצד.  גם אתם יכולים להצטרף ולתרום לפרוייקט ב- CodePlex.

דוגמא ליישום רוזלין – בניית אפליקציה עם מנגנון מקרו להתאמה אישית בדומה לאופיס.

איך "רוזלין" עוזרת לי להוסיף גמישות לאפליקציה? איך "רוזלין" חוסכת זמן בפיתוח? ואיך "רוזלין" מאפשרת קסטומיזציה עבור מספר לקוחות שונים?

תמיד ראיתי באפליקציות הOFFICE מודל לחיקוי. היכולת התאמה אישית על ידי כתיבת מקרו (Macro) הינה יכולת מאוד יפה שרציתי לשלב באפליקציות שפיתחתי. אבל מצד שני לפתח יכולת כזו מאפס ואחרי זה לשלב באפליקציה זה מאוד מסובך ודורש זמן רב. ופה באה לעזרתנו "רוזלין".

בפוסט זה אני רוצה להראות איך בזמן קצר אפשר לבנות אפליקציה עם מנגנון מקרו בפנים. במקרה שלנו מקרו יהיו כותבים בשפת C# (ניתן לעבוד גם עם VB) לצורך כך אני אשתמש בScripting API של Roslyn כאשר הוא חלק קטן ממגוון רחב של ממשקים ש "רוזלין" חושפת.

בואו נתחיל… נבנה אפליקציה קטנה שמשלבת מנוע מקרו. אני בחרתי לבנות אפליקציית WinForms אבל זו יכולה להיות גם אפליקציה WPF או MVC.

שלב ראשון – בניית מודל אובייקטים

כדי שיהיה נקודות חיבור בין האפליקציה והקוד של המקרו צריך להגדיר מודל אובייקטים שאיתם ניתן לעבוד במקרו. נתחיל עם אובייקט root שנתתי ל classשלו שם HostObject. ל- HostObject יהיה במערכת רק מופע אחד (ניתן להשתמש בתבנית עיצוב Singleton) ותפקידו של אובייקט זה הוא עבודה מול שירותים של אפליקציה. האפליקציה במקרה שלנו חושפת שרות יחיד – הדפסה ללוג.

public class HostObject

    {

        /// <summary>

        /// HostObject ctor

        /// </summary>

        /// <param name="logger">TextBox will be used for logging</param>

        public HostObject(System.Windows.Forms.TextBox logger)

        {

            _textBoxLog = logger;

        }

 

        private System.Windows.Forms.TextBox _textBoxLog;

 

        

        private List<WorkItem> _listWorkItems = new List<WorkItem>();

 

        /// <summary>

        /// List of Work Items HostObject contains

        /// </summary>

        public IList<WorkItem> WorkItems { get { return this._listWorkItems; } }

 

        /// <summary>

        /// Application service exposed by HostObject

        /// can be used by Macro writer

        /// </summary>

        /// <param name="text">text to write to log</param>

        public void PrintLog(string text)

        {

            _textBoxLog.Text = string.Format("{0}\r\n{1}", _textBoxLog.Text, text);

        }

    }

בנוסף אני רוצה להגדיר class ששמו WorkItem והוא ישמש אותי לביצוע פעולות ויהיה חלק ממודל אובייקטים שלי. ה-CLASS יהיה בעל פונקציה יחידה DoWork

public class WorkItem

    {

        public WorkItem(string name)

        {

            this._name = name;

        }

        private string _name;

        public string DoWork()

        {

            return string.Format("Work Done by {0}", this._name);

        }

 

    }

}

שלב שני – שילוב המנוע של C# באפליקציה

כדי לשלב מנוע מקרו מבוסס C# באפליקציה שלי אני אשתמש בשתי classים של Scripting API של Roslyn:

Roslyn.Scripting.CSharp.ScriptEngine – מייצג את קונטקסט עבודה של זמן ריצה לסקריפטים C# (מנוע)

Roslyn.Scripting.Session – ייצוג של הפעלה אינטראקטיבית בקונטקסט של זמן ריצה

דבר ראשון עלי לבנות מנוע. תחת המנוע להגדיר Session כאשר אני צריך להעביר ל – Session אובייקט root של מודל האובייקטים. אחרי זה להגדיר עבור ה – Session לאילו ספריות אני רוצה להגדיר Reference ובסופו של דבר להעביר קוד שאני רוצה לבצע.

להלן דוגמה של קוד המשתמשת במודל האובייקטים שהגדרנו בשלב הראשון ומאפשרת להריץ קוד המוגדר על ידי המשתמש של האפליקציה. כאן אנחנו מעתיקים References של אפליקציה ל – Session. ניתן להגדיר דברים שהם ספציפיים עבור ה – Session וכך לצמצם יכולות של משתמש באפליקציה.

var hostObject = new HostObject(this.textBoxLog);

            

            var engine = new Roslyn.Scripting.CSharp.ScriptEngine();

            var session = engine.CreateSession(hostObject);

 

            var assemblies = AppDomain.CurrentDomain.GetAssemblies();

            foreach (var assembly in assemblies)

            {

                session.AddReference(assembly);

            }

           

 

            try

            {

 

                session.Execute(this.textBoxCode.Text);

            }

            catch(Exception ex)

            {

                hostObject.PrintLog(ex.Message);

            }

ולבסוף דוגמת ממשק משתמש של אפליקציה אחרי שהרצנו קוד שהוקש על ידי המשתמש של האפליקציה.

1

 

מפתחים אפליקציות ל- Windows Azure? אתם מוזמנים לפורום שלנו בעברית בנושא!

 

vladimirהפוסט נכתב ע"י ולדימיר בוקלן, יועץ בקבוצת היועצים של מיקרוסופט (MCS ) העוסקת בייעוץ בתחומי ארכיטקטורה, פיתוח, CRM ו- ALM.

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *