Arbeiten mit Excel in .NET unabhängig von der installierten Version von Excel
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.GetTypeFromProgID
Activator.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.