Práce s Excelem v .NET nezávisle na nainstalované verzi Excelu
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.GetTypeFromProgID
Activator.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.