Práce s Excelem v .NET nezávisle na nainstalované verzi Excelu

Stránky aktualizovány :
Datum vytvoření stránky :

Provozní prostředí

Visual Studio
  • Visual Studio 2022
.SÍŤ
  • .NET 6.0
Windows
  • Systém Windows 7
  • Systém Windows 11
Vynikat
  • Microsoft 365
  • Kancelář Office 2007

Požadavky

Windows
  • Jedna z verzí
Vynikat
  • Jedna z verzí

Problémy s knihovnami, které pracují s Excelem

Jedním ze způsobů, jak programově pracovat s Excelem, je Microsoft.Office.Interop.Excel odkazovat na rozhraní . Je to podobné jako při práci přímo s aplikací Excel přes COM, takže se to mírně liší od práce s daty v souboru Excel. Předpokladem je, že Excel musí být nainstalován v prostředí, které má být spuštěno, ale mnoho funkcí Excelu je k dispozici ze strany programu.

Microsoft.Office.Interop.Excel Pokud program používáte, budete si myslet, že program bude napsán následujícím způsobem.

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

Je nepříjemné pokaždé uvolňovat zdroje, ale protože můžete použít připravené třídy, můžete zpracování Excelu provádět poměrně intuitivně.

Nevýhodou však je, že verze knihovny, na kterou program odkazuje, se musí shodovat nebo být kompatibilní s verzí Excelu nainstalovanou v prostředí, ve kterém je spuštěna. Například program vytvořený odkazem na interní knihovnu Excelu verze 15.0 (2013) se dá spustit jenom v případě, že je nainstalovaný Excel 2013. Pokud chcete, aby váš program běžel v mnoha prostředích, možná budete muset udržovat instalaci aplikace Excel spuštěnou v konzistentní verzi.

Pokud je taková operace možná, je to v pořádku, ale pokud je nainstalovaná verze Excelu jiná, nelze jí vyhovět. Proto je nutné udělat něco na straně programu.

Dynamické odkazování na knihovny pomocí dynamic namísto přímého odkazování na ně

Problém v tomto případě nastává, protože verze knihovny je odkazována jako pevná při vytváření programu. To znamená, že místo určení verze v době vytvoření programu je nutné určit verzi v době provádění programu.

Existuje několik způsobů, jak to udělat, ale tentokrát to vyřešíme pomocí "" "" a "Type.GetTypeFromProgIDActivator.CreateInstance".dynamic

Za normálních okolností je v jazyce C# nutné určit informace o typu v době vytváření programu, ale pokud je dynamic typ , lze typ určit v době provádění. object Na rozdíl od dynamic typů, pokud je instance nastavená na proměnnou třídou, můžete také volat metody a vlastnosti této třídy. Vzhledem k tomu, že to, co jde do proměnné, je určeno v načasování provádění, dojde v době provádění k chybě, pokud není zadána žádná metoda.

Kód vytvořený pomocí těchto je následující.

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

Typ deklarace proměnné je , a Excel.Application vytvoření proměnné je mírně odlišné, ale zbytek kódu je dynamic téměř znovu použit.

Vzhledem k tomu, že výše uvedený kód neodkazuje na knihovnu aplikace Excel, není možné použít informace o cílové třídě související s aplikací Excel. Proto je typ proměnné all dynamic . Vzhledem k tomu, že nemůžeme odkazovat přímo na třídu,Excel.Application místo toho Excel.Application Type.GetTypeFromProgID získáme informace Activator.CreateInstance o typu a předáme je k vytvoření Excel.Application instance . Mimochodem, v prostředí, kde Excel není nainstalován, jej nemůžete dostat dovnitř Type , takže je možné izolovat, Type.GetTypeFromProgID zda je nainstalován nebo ne.

dynamic Nevýhodou použití je, že třídu nelze určit při sestavování programu. IntelliSense, což je funkce dokončování při zadávání kódu, nezobrazuje názvy metod a názvy vlastností. Může být méně těžkopádné psát kód s odkazem na knihovnu na začátku a nahradit ho dynamic později.

Při spuštění v prostředí Microsoft 365 můžete potvrdit, že se projeví následujícím způsobem.

Následující je výsledkem spuštění v mnohem starší verzi sady Office 2007. Pokud nepoužíváte funkci, která funguje pouze v konkrétní verzi, můžete ji zprovoznit poměrně široce.

Mimochodem, pokud jej spustíte v prostředí, kde není nainstalován Excel, můžete správně určit, že jej nelze zpracovat.