Arbeiten mit Excel in .NET unabhängig von der installierten Version von Excel

Diese Seite wurde aktualisiert :
Erstellungsdatum der Seite :

Betriebsumgebung

Visual Studio
  • Visual Studio 2022
.NETTO
  • .NET 6.0
Fenster
  • Windows 7 (Englisch)
  • Windows 11
Ausstechen
  • Microsoft 365
  • Office 2007

Voraussetzungen

Fenster
  • Eine der Versionen
Ausstechen
  • Eine der Versionen

Probleme mit Bibliotheken, die mit Excel arbeiten

Eine Möglichkeit, programmgesteuert mit Excel zu interagieren, besteht darin Microsoft.Office.Interop.Excel , auf . Dies ähnelt dem direkten Arbeiten mit der Excel-Anwendung über COM und unterscheidet sich daher geringfügig von der Arbeit mit Daten in einer Excel-Datei. Als Voraussetzung muss Excel in der auszuführenden Umgebung installiert werden, aber viele Funktionen von Excel stehen programmseitig zur Verfügung.

Microsoft.Office.Interop.Excel Wenn Sie das Programm verwenden, werden Sie denken, dass das Programm auf folgende Weise geschrieben wird.

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

Es ist mühsam, jedes Mal Ressourcen freigeben zu müssen, aber da Sie die vorbereiteten Klassen verwenden können, können Sie die Excel-Verarbeitung relativ intuitiv durchführen.

Der Nachteil besteht jedoch darin, dass die Version der Bibliothek, auf die das Programm verweist, mit der Version von Excel übereinstimmen oder mit ihr kompatibel sein muss, die in der Umgebung installiert ist, in der es ausgeführt wird. Beispielsweise kann ein Programm, das durch Verweisen auf die interne Excel-Bibliothek der Version 15.0 (2013) erstellt wurde, nur ausgeführt werden, wenn Excel 2013 installiert ist. Wenn Sie möchten, dass Ihr Programm in vielen Umgebungen ausgeführt wird, müssen Sie Ihre Excel-Installation möglicherweise in einer konsistenten Version ausführen.

Wenn ein solcher Vorgang möglich ist, ist er in Ordnung, aber wenn die installierte Version von Excel unterschiedlich ist, kann er nicht berücksichtigt werden. Daher ist es notwendig, programmseitig etwas zu tun.

Dynamisches Verweisen auf Bibliotheken mit dynamic, anstatt direkt auf sie zu verweisen

Das Problem tritt in diesem Fall auf, weil die Bibliotheksversion beim Erstellen des Programms fixiert wird. Das bedeutet, dass anstelle der Ermittlung der Version zum Zeitpunkt der Programmerstellung die Version zum Zeitpunkt der Programmausführung ermittelt werden muss.

Es gibt mehrere Möglichkeiten, dies zu tun, aber dieses Mal werden wir es mit "" "" und ""Type.GetTypeFromProgIDActivator.CreateInstance lösen.dynamic

Normalerweise ist es in C# erforderlich, die Typinformationen zum Zeitpunkt der Programmerstellung zu bestimmen, aber wenn der Typ ist dynamic , kann der Typ zum Zeitpunkt der Ausführung bestimmt werden. object Im Gegensatz zu dynamic Typen können Sie, wenn die auf eine Variable festgelegte Instanz eine Klasse ist, auch die Methoden und Eigenschaften dieser Klasse aufrufen. Da jedoch festgelegt wird, was in die Variable zum Zeitpunkt der Ausführung eingeht, tritt zur Ausführungszeit ein Fehler auf, wenn keine Methode angegeben ist.

Der Code, der mit diesen erstellt wurde, lautet wie folgt.

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

Der Typ der Deklaration der Variablen ist , und Excel.Application die Erstellung von ist dynamic etwas anders, aber der Rest des Codes wird fast wiederverwendet.

Da der obige Code nicht auf die Excel-Bibliothek verweist, ist es nicht möglich, die Excel-bezogenen Zielklasseninformationen zu verwenden. Daher ist der Typ der Variablen alle dynamic . Da wir nicht direkt auf die Klasse verweisen können, rufen wir stattdessen Type.GetTypeFromProgID Excel.Application die Typinformationen Activator.CreateInstance ab und übergeben sie an,Excel.Application um eine Instanz von zu erstellenExcel.Application. Übrigens, in einer Umgebung, in der Excel nicht installiert ist, können Sie es nicht erhalten, daher ist es möglich, zu isolieren, Type.GetTypeFromProgID ob es installiert ist oder nicht Type .

dynamic Der Nachteil der Verwendung besteht darin, dass die Klasse beim Erstellen des Programms nicht bestimmt werden kann. IntelliSense, bei dem es sich um eine Vervollständigungsfunktion bei der Eingabe von Code handelt, zeigt keine Methodennamen und Eigenschaftsnamen an. Es kann weniger umständlich sein, am Anfang Code mit Bezug auf die Bibliothek zu schreiben und ihn später durch ihn zu dynamic ersetzen.

Wenn Sie in einer Microsoft 365-Umgebung ausgeführt werden, können Sie bestätigen, dass dies wie folgt widergespiegelt wird.

Das Folgende ist das Ergebnis der Ausführung unter einer viel älteren Version von Office 2007. Wenn Sie eine Funktion nicht verwenden, die nur in einer bestimmten Version funktioniert, können Sie sie recht breit funktionieren lassen.

Übrigens: Wenn Sie es in einer Umgebung ausführen, in der Excel nicht installiert ist, können Sie korrekt feststellen, dass es nicht verarbeitet werden kann.