Tag Archive for COM Interop

האם עוד צריך את VB.NET לתכנת מול אופיס?

עברו כמה שנים מאז שעבדתי עם Visual Basic.NET, והייתי בטוח שבימינו, ב-2013, נגמרו כבר הויכוחים של “איזו שפה יותר טובה”. שתיהן שפות עם יכולות דומות, והבחירה ביניהן היא בעיקר העדפה סגנונית. אבל מידי פעם אני עדיין רואה בפורומים או ב-Stack Overflow שאלה בנוגע ליתרונות של שפה אחת על השניה, וספציפית על יכולות ה-COM Interop של VB. האם היא באמת שפה נוחה יותר?

המצב טרום .NET 4.0

לפני .NET 4.0 (שיצאה, יש להזכיר, לפני כמעט 3 שנים), התשובה היתה “כן”, אם כי “כן” קצת דחוק. VB הגיעה מתוך עולם ה-Late Binding, ולא היה לה בעיה להעביר לרכיב רק חלק מהפרמטרים שהם צריכים, ולדאוג לשאר לברירות מחדל מאחורי הקלעים. היתרון הזה היה בולט במיוחד כשעובדים מול אובייקטים של אופיס, שמכילים מתודות שמקבלות חמישה, עשרה, ולפעמים שישה-עשר פרמטרים אופציונאליים, כשברוב המקרים אנחנו נרצה להעביר רק אחד או שניים מהם, אם בכלל. ההבדל בין C# ל-VB במקרה כזה הוא ההבדל בין הקוד הזה ב-C#:

Code Snippet
  1. myWordDocument.SaveAs(ref fileName, ref missingValue,
  2.                  ref missingValue, ref missingValue,
  3.                  ref missingValue, ref missingValue,
  4.                  ref missingValue, ref missingValue,
  5.                  ref missingValue, ref missingValue,
  6.                  ref missingValue, ref missingValue,
  7.                  ref missingValue, ref missingValue,
  8.                  ref missingValue, ref missingValue);

לבין זה ב-VB:

Code Snippet
  1. MyWordDocument.SaveAs(FileName: fileName)

שזה, אתם חייבים להודות, הבדל לא קטן.

אבל מצד שני, לא כל ממשק COM עובד ככה. למען האמת, בכל שנותי אני חושב שנתקלתי בסגנון כתיבה הזה רק בספריות של אופיס, ולא בשום רכיב אחר, בין אם של מיקרוסופט (כמו רכיבי DirectShow שאיתם עבדתי לאחרונה) או של חברות אחרות. ברוב המקרים, לעשות COM Interop ב-C# פשוט באותה מידה כמו ב-VB.

.NET 4.0 – גם C# זוכה ליחס

היתרון הקטן הזה של VB נהיה גם הוא פחות רלבנטי החל מ-C# 4.0 ו-Visual Studio 2010, משתי סיבות:

הראשונה היא מילת הקסם שהתווספה לה לשפה, dynamic. כשאנחנו מגדירים אובייקט כדינאמי, אנחנו מוותרים על הרבה מה-static type checking שהקומפיילר עושה בשבילנו, ונותנים למנגנון ה-late binding (שסופח ל-C# באמצעות ה-DLR, ה-Dynamic Language Runtime שנבנה לתמוך בשפות דינאמיות כמו Python או Ruby) לעשות בשבילנו את העבודה ב-runtime. מכיוון שיש late binding, אפשר להתעלם מהפרמטרים המיותרים ולתת ל-DLR להבין לבד מה לחבר לאיפה. אפשר למצוא הסבר כללי על שימוש ב-dynamic במאמר הזה, והסבר יותר ספציפי על השימוש בו ל-COM Interop במאמר הזה.

אבל אם אנחנו שקלנו לעבור ל-VB רק בשביל לעבוד מול רכיבי אופיס, אז C# 4.0 מאפשר לנו להקל על החיים גם בלי לצלול לעולם העכור של dynamic languages. אנחנו עדיין לא יכולים להתעלם מ-ref parameters במתודות של מחלקות, אבל אנחנו כן יכולים להתעלם מהפרמטרים הללו בקריאות למתודות על interfaces. אני לא יכול להגיד שאני מבין לגמרי למה זה ככה (טרם התעמקתי) אבל זה אומר שאם מה שיש לנו ביד זה לא אובייקט DocumentClass של אופיס, אלא interface מסוג Document, אז אפשר לקרוא למתודות שעליו כמו ב-VB.

לנוחותינו, ספריות ה-Interop של אופיס חושפות לנו את ה-interfaces האלה, דרך property בשם InnerObject שיש על רוב האובייקטים המעניינים. (כן, זה property בשם InnerObject שחושף את ה-Interface. אני יודע. זה מבלבל. זה מה יש). אז את הקוד שכתבנו למעלה  אפשר להחליף, ב-C# 4.0, בזה:

Code Snippet
  1. myWordDocument.InnerObject.SaveAs(FileName: fileName);

וזהו! אמנם לא כל אובייקט של אופיס זוכה ל-InnerObject הזה, אבל המרכזיים והגדולים (שהם גם אלה עם המתודות המפלצתיות) דווקא כן. ואם אין ברירה, נעבוד גם עם dynamic – או עם Missing.Value.

אז מתי בכל זאת VB?

כל המלל לעיל לא נועד לשכנע מישהו לבחור דווקא ב-C# או דווקא לא ב-VB. שתי השפות יכולות לעשות פחות או יותר כל אחת את מה שהשניה יכולה לעשות, והבחירה בה צריכה להיות של העדפה אישית לסגנון כתיבה, לא בגלל יכולת קריטיות לכאן או לכאן. זה מה שניסיתי להעביר כאן – כמו ש-VB יישרה קו עם C# לאורך השנים בכמה פיצ’רים שהיו חסרים, כך גם C# השלימה את החסר לה בנוגע לעבודה עם אופיס. הבחירה היא, שוב, סגנונית בלבד.