کار با اکسل در دات نت مستقل از نسخه نصب شده اکسل

صفحه به روز شده :
تاریخ ایجاد صفحه :

محیط عملیاتی

ویژوال استودیو
  • ویژوال استودیو 2022
.خالص
  • دات نت 6.0
ویندوز
  • ویندوز 7
  • ویندوز 11
اکسل
  • مایکروسافت 365
  • دفتر 2007

پیش نیازها

ویندوز
  • یکی از نسخه های
اکسل
  • یکی از نسخه های

مشکلات کتابخانه هایی که با اکسل کار می کنند

یکی از راه های برنامه ریزی تعامل با اکسل، مرجع است Microsoft.Office.Interop.Excel . این شبیه به کار مستقیم با برنامه اکسل از طریق COM است، بنابراین کمی متفاوت از کار با داده ها در یک فایل اکسل است. به عنوان یک فرض، اکسل باید در محیط نصب شود تا اجرا شود، اما بسیاری از توابع اکسل از طرف برنامه در دسترس هستند.

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);
}

این مشکل است که هر بار منابع را ازاد کنید، اما از انجا که می توانید از کلاس های اماده استفاده کنید، می توانید پردازش اکسل را نسبتا مستقیم انجام دهید.

با این حال، اشکال این است که نسخه کتابخانه اشاره شده توسط برنامه باید با نسخه اکسل نصب شده در محیطی که در ان اجرا می شود مطابقت داشته باشد یا سازگار باشد. به عنوان مثال، یک برنامه ایجاد شده با اشاره به نسخه داخلی 15.0 (2013) کتابخانه اکسل تنها زمانی می تواند اجرا شود که اکسل 2013 نصب شود. اگر می خواهید برنامه شما در بسیاری از محیط ها اجرا شود، ممکن است لازم باشد نصب اکسل خود را بر روی یک نسخه سازگار اجرا کنید.

اگر چنین عملیاتی امکان پذیر باشد، خوب است، اما اگر نسخه نصب شده اکسل متفاوت باشد، نمی توان ان را جایگزین کرد. بنابراین، لازم است کاری در سمت برنامه انجام شود.

ارجاع کتابخانه ها به صورت پویا به جای ارجاع مستقیم به انها

مشکل در این مورد به این دلیل رخ می دهد که نسخه کتابخانه زمانی که برنامه ایجاد می شود ثابت می شود. این بدان معنی است که به جای تعیین نسخه در زمان ایجاد برنامه، لازم است نسخه را در زمان اجرای برنامه تعیین کنید.

راه های مختلفی برای انجام این کار وجود دارد، اما این بار ما ان را با استفاده از "" "" و "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 ایجاد ان کمی متفاوت است، اما بقیه کد تقریبا دوباره استفاده می شود.

از انجا که کد بالا به کتابخانه اکسل اشاره نمی کند، امکان استفاده از اطلاعات کلاس مربوط به اکسل وجود ندارد. بنابراین، نوع متغیر همه dynamic است. همچنین، از انجا که ما نمی توانیم به طور مستقیم به کلاس اشاره کنیم،Excel.Application در عوض Excel.Application Type.GetTypeFromProgID اطلاعات Activator.CreateInstance Type را دریافت می کنیم و ان را برای ایجاد Excel.Application یک نمونه از . به هر حال، در محیطی که اکسل نصب نشده است، Type.GetTypeFromProgID شما نمی توانید ان را وارد Type کنید، بنابراین می توان جدا کرد که ایا نصب شده است یا نه.

dynamic نقطه ضعف استفاده از این است که کلاس را نمی توان در هنگام ساخت برنامه تعیین کرد. Intellisense، که یک تابع تکمیل در هنگام وارد کردن کد است، نام روش و نام ویژگی ها را نمایش نمی دهد. ممکن است نوشتن کد با اشاره به کتابخانه در ابتدا و جایگزینی ان با dynamic بعدا کمتر دشوار باشد.

هنگامی که در محیط Microsoft 365 اجرا می شود، می توانید تایید کنید که به شرح زیر منعکس شده است.

در زیر نتیجه اجرای ان در نسخه بسیار قدیمی Office 2007 است. اگر از تابعی استفاده نکنید که فقط در یک نسخه خاص کار می کند، می توانید ان را به طور گسترده ای کار کنید.

به هر حال، اگر ان را در محیطی اجرا کنید که اکسل نصب نشده است، می توانید به درستی تعیین کنید که نمی توان ان را پردازش کرد.