עבודה עם Excel ב- .NET ללא תלות בגירסה המותקנת של Excel

עודכן דף :
תאריך יצירת דף :

סביבת הפעלה

Visual Studio
  • Visual Studio 2022
.רשת
  • .NET 6.0
חלונות
  • חלונות 7
  • חלונות 11
הצטיין
  • Microsoft 365
  • משרד 2007

דרישות מוקדמות

חלונות
  • אחת הגרסאות
הצטיין
  • אחת הגרסאות

בעיות בספריות הפועלות עם Excel

דרך אחת לקיים אינטראקציה תוכניתית עם Excel היא Microsoft.Office.Interop.Excel להפנות . הדבר דומה לעבודה ישירה עם יישום Excel באמצעות COM, ולכן הוא שונה במקצת מעבודה עם נתונים בקובץ Excel. כהנחת יסוד, Excel חייב להיות מותקן בסביבה כדי להיות מופעל, אבל פונקציות רבות של Excel זמינים מצד התוכנית.

Microsoft.Office.Interop.Excel אם אתה משתמש בתוכנית, תחשוב שהתוכנית תיכתב באופן הבא.

// 実行プログラムの場所にある Excel ファイル
var excelFilePath = $@"{Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName)}\Sample.xlsx";

// Excel のオブジェクトは参照したら必ず解放する必要があります。
// 解放しないと Excel のプロセスが残り続けます。
Microsoft.Office.Interop.Excel.Application? excel = null;
Microsoft.Office.Interop.Excel.Workbooks? books = null;
Microsoft.Office.Interop.Excel.Workbook? book = null;
Microsoft.Office.Interop.Excel.Sheets? sheets = null;
Microsoft.Office.Interop.Excel.Worksheet? sheet = null;
Microsoft.Office.Interop.Excel.Range? cells = null;
Microsoft.Office.Interop.Excel.Range? range1 = null;
Microsoft.Office.Interop.Excel.Range? range2 = null;
try
{
  // Excel アプリケーションを生成(起動)します
  excel = new Microsoft.Office.Interop.Excel.Application
  {
    DisplayAlerts = false
  };

  // ワークブック一覧を参照します。参照する場合は必ず変数に保持します
  books = excel.Workbooks;

  // Excel ファイルを開きます
  book = books.Open(excelFilePath);

  // シート一覧を参照するので変数に保持します
  sheets = book.Worksheets;

  // シートを参照します。最初のシートは 1 になります
  sheet = (Microsoft.Office.Interop.Excel.Worksheet)sheets[1];

  // セル一覧を参照します
  cells = sheet.Cells;

  // 左上のセルを参照します。一番左上は [1, 1] になります
  range1 = (Microsoft.Office.Interop.Excel.Range)cells[1, 1];

  // セルの値を取得します。値の取得なので後で解放する必要はありません
  var value = (int)range1.Value;

  // 下のセルを参照します
  range2 = (Microsoft.Office.Interop.Excel.Range)cells[2, 1];

  // 日付分足してセットします
  range2.Value = DateTime.Now.Day + value;

  // 保存して閉じます
  book.Close(SaveChanges: true);

  Console.WriteLine("処理が完了しました。");
}
catch (Exception ex)
{
  // 閉じていなければ保存せずに閉じます
  // 開きっぱなしだと Excel 起動時に保存されていないデータとして表示される場合があります
  if (book != null) book.Close(SaveChanges: false);

  Console.WriteLine("処理が失敗しました。");
  Console.WriteLine(ex);
}
finally
{
  // 終了していなければ終了します
  if (excel != null) excel.Quit();

  // 例外が発生した場合でも必ずリソースを解放するようにします
  if (range1 != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(range1);
  if (range2 != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(range2);
  if (cells != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(cells);
  if (sheet != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sheet);
  if (sheets != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sheets);
  if (book != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(book);
  if (books != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(books);
  if (excel != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excel);
}

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

החיסרון, עם זאת, הוא שגירסת הספריה שאליה מפנה התוכנית חייבת להתאים או להיות תואמת לגירסת Excel המותקנת בסביבה שבה היא פועלת. לדוגמה, תוכנית שנוצרה על-ידי הפניה לספריה הפנימית של Excel בגירסה 15.0 (2013) יכולה לפעול רק כאשר Excel 2013 מותקן. אם ברצונך שהתוכנית תפעל בסביבות רבות, ייתכן שיהיה עליך להפעיל את התקנת Excel בגירסה עקבית.

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

הפניה דינמית לספריות עם דינמיות במקום הפניה ישירה אליהן

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

ישנן מספר דרכים לעשות זאת, אך הפעם נפתור זאת באמצעות "", "" ו- "Type.GetTypeFromProgIDActivator.CreateInstance".dynamic

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

הקוד שנוצר באמצעות אלה הוא כדלקמן.

// 実行プログラムの場所にある Excel ファイル
var excelFilePath = $@"{Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName)}\Sample.xlsx";

// Excel のオブジェクトは参照したら必ず解放する必要があります。
// 解放しないと Excel のプロセスが残り続けます。
dynamic? excel = null;
dynamic? books = null;
dynamic? book = null;
dynamic? sheets = null;
dynamic? sheet = null;
dynamic? cells = null;
dynamic? range1 = null;
dynamic? range2 = null;
try
{
  // Excel.Application の Type を取得
  var type = Type.GetTypeFromProgID("Excel.Application");
  if (type == null)
  {
    Console.WriteLine("Excel がインストールされていません。");
    return;
  }

  // Excel アプリケーションを生成(起動)します
  excel = Activator.CreateInstance(type);
  if (excel == null)
  {
    Console.WriteLine("Excel.Application のインスタンスの生成に失敗しました。");
    return;
  }
  excel.DisplayAlerts = false;

  // ワークブック一覧を参照します。参照する場合は必ず変数に保持します
  books = excel.Workbooks;

  // Excel ファイルを開きます
  book = books.Open(excelFilePath);

  // シート一覧を参照するので変数に保持します
  sheets = book.Worksheets;

  // シートを参照します。最初のシートは 1 になります
  sheet = (Microsoft.Office.Interop.Excel.Worksheet)sheets[1];

  // セル一覧を参照します
  cells = sheet.Cells;

  // 左上のセルを参照します。一番左上は [1, 1] になります
  range1 = (Microsoft.Office.Interop.Excel.Range)cells[1, 1];

  // セルの値を取得します。値の取得なので後で解放する必要はありません
  var value = (int)range1.Value;

  // 下のセルを参照します
  range2 = (Microsoft.Office.Interop.Excel.Range)cells[2, 1];

  // 日付分足してセットします
  range2.Value = DateTime.Now.Day + value;

  // 保存して閉じます
  book.Close(SaveChanges: true);

  Console.WriteLine("処理が完了しました。");
}
catch (Exception ex)
{
  // 閉じていなければ保存せずに閉じます
  // 開きっぱなしだと Excel 起動時に保存されていないデータとして表示される場合があります
  if (book != null) book.Close(SaveChanges: false);

  Console.WriteLine("処理が失敗しました。");
  Console.WriteLine(ex);
}
finally
{
  // 終了していなければ終了します
  if (excel != null) excel.Quit();

  // 例外が発生した場合でも必ずリソースを解放するようにします
  if (range1 != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(range1);
  if (range2 != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(range2);
  if (cells != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(cells);
  if (sheet != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sheet);
  if (sheets != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sheets);
  if (book != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(book);
  if (books != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(books);
  if (excel != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excel);
}

סוג ההצהרה של המשתנה הוא dynamic , והיצירה Excel.Application של שונה במקצת, אך שאר הקוד נמצא כמעט בשימוש חוזר.

מאחר שהקוד לעיל אינו מתייחס לספריית Excel, לא ניתן להשתמש במידע המחלקה הקשור ל- Excel המהווה יעד. לכן, סוג המשתנה הוא כל dynamic . כמו כן, מכיוון שאיננו יכולים להפנות ישירות למחלקה,Excel.Application במקום זאת Type.GetTypeFromProgID Excel.Application אנו מכניסים את המידע Activator.CreateInstance Type ומעבירים אותו אל כדי ליצור Excel.Application מופע של . אגב, בסביבה שבה Excel אינו מותקן, Type.GetTypeFromProgID אתה לא יכול לקבל את זה , Type ולכן ניתן לבודד אם הוא מותקן או לא.

dynamic החיסרון בשימוש הוא שלא ניתן לקבוע את הכיתה בעת בניית התוכנית. Intellisense, שהיא פונקציית השלמה בעת הזנת קוד, אינה מציגה שמות שיטות ושמות מאפיינים. זה עשוי להיות פחות מסורבל לכתוב קוד עם התייחסות לספרייה בהתחלה ולהחליף אותו מאוחר dynamic יותר.

בעת הפעלה בסביבת Microsoft 365, באפשרותך לאשר שהיא משתקפת באופן הבא.

להלן התוצאה של הפעלתו בגירסה ישנה בהרבה של Office 2007. אם אינך משתמש בפונקציה שפועלת רק בגירסה ספציפית, תוכל לגרום לה לפעול באופן נרחב למדי.

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