Lucrați cu Excel în .NET independent de versiunea instalată de Excel

Pagina actualizată :
Data creării paginii :

Mediu de operare

Visual Studio
  • Visual Studio 2022
.NET
  • .NET 6.0
Windows
  • Ferestre 7
  • Ferestre 11
Excela
  • Microsoft 365
  • Birou 2007

Cerințe preliminare

Windows
  • Una dintre versiuni
Excela
  • Una dintre versiuni

Probleme cu bibliotecile care funcționează cu Excel

O modalitate de a interacționa programatic cu Excel este Microsoft.Office.Interop.Excel să faceți referire . Acest lucru este similar cu lucrul direct cu aplicația Excel prin COM, deci este ușor diferit de lucrul cu datele dintr-un fișier Excel. Ca premisă, Excel trebuie instalat în mediul care urmează să fie executat, dar multe funcții ale Excel sunt disponibile din partea programului.

Microsoft.Office.Interop.Excel Dacă utilizați programul, veți crede că programul va fi scris în felul următor.

// 実行プログラムの場所にある 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);
}

Este dificil să trebuiască să eliberați resurse de fiecare dată, dar din moment ce puteți utiliza cursurile pregătite, puteți efectua procesarea Excel relativ intuitiv.

Cu toate acestea, dezavantajul este că versiunea bibliotecii la care face referire programul trebuie să se potrivească sau să fie compatibilă cu versiunea de Excel instalată în mediul în care rulează. De exemplu, un program creat făcând referire la versiunea internă 15.0 (2013) bibliotecă de Excel se poate executa numai atunci când este instalat Excel 2013. Dacă doriți ca programul să se execute în mai multe medii, poate fi necesar să păstrați instalarea Excel care rulează pe o versiune consecventă.

Dacă o astfel de operație este posibilă, este bine, dar dacă versiunea instalată de Excel este diferită, nu poate fi găzduită. Prin urmare, este necesar să faceți ceva pe partea programului.

Referențierea bibliotecilor în mod dinamic cu dinamic, în loc să se facă referire directă la acestea

Problema în acest caz apare deoarece se face referire la versiunea bibliotecii fixată atunci când se creează programul. Aceasta înseamnă că, în loc să se determine versiunea în momentul creării programului, este necesar să se determine versiunea în momentul executării programului.

Există mai multe modalități de a face acest lucru, dar de data aceasta o vom rezolva folosind "" "" și "Type.GetTypeFromProgIDActivator.CreateInstance".dynamic

În mod normal, în C#, este necesar să se determine informațiile de tip în momentul creării programului, dar dacă tipul este dynamic , tipul poate fi determinat în momentul execuției. object Spre deosebire dynamic de tipuri, dacă instanța setată la o variabilă este o clasă, puteți apela și metodele și proprietățile acelei clase. Cu toate acestea, deoarece ceea ce intră în variabilă este determinat în momentul execuției, va apărea o eroare la momentul execuției dacă nu există o metodă specificată.

Codul creat folosind acestea este după cum urmează.

// 実行プログラムの場所にある 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);
}

Tipul declarației variabilei este , iar Excel.Application crearea este ușor diferită, dar restul codului este dynamic aproape reutilizat.

Deoarece codul de mai sus nu se referă la biblioteca Excel, nu este posibil să utilizați informațiile de clasă țintă legate de Excel. Prin urmare, tipul variabilei este tot dynamic . De asemenea, deoarece nu putem face referire directă la clasă,Excel.Application obținem în schimb Excel.Application Type.GetTypeFromProgID informațiile Activator.CreateInstance de tip și le transmitem pentru a crea Excel.Application o instanță de . Apropo, într-un mediu în care Excel nu este instalat, nu îl puteți obține , Type.GetTypeFromProgID Type deci este posibil să se izoleze dacă este instalat sau nu.

dynamic Dezavantajul utilizării este că clasa nu poate fi determinată la construirea programului. Intellisense, care este o funcție de completare la introducerea codului, nu afișează numele metodelor și numele proprietăților. Poate fi mai puțin greoi să scrieți cod cu referire la bibliotecă la început și să îl înlocuiți cu dynamic mai târziu.

Atunci când rulați într-un mediu Microsoft 365, puteți confirma că acesta este reflectat după cum urmează.

Următorul este rezultatul rulării acestuia pe o versiune mult mai veche de Office 2007. Dacă nu utilizați o funcție care funcționează numai într-o anumită versiune, o puteți face să funcționeze destul de larg.

Apropo, dacă îl executați într-un mediu în care Excel nu este instalat, puteți determina corect că nu poate fi procesat.