Töötage Exceliga .NET-is sõltumatult installitud Exceli versioonist

Lehekülg uuendatud :
Lehe loomise kuupäev :

Töökeskkond

Visuaalne stuudio
  • Visual Studio 2022
.NET
  • .NET 6.0
Windows
  • Windows 7
  • Windows 11
Excel
  • Microsoft 365
  • Office 2007

Eeltingimused

Windows
  • Üks versioonidest
Excel
  • Üks versioonidest

Probleemid Exceliga töötavate teekidega

Üks võimalus Exceliga programmiliselt suhelda on Microsoft.Office.Interop.Excel viidata . See sarnaneb töötamisega otse Exceli rakendusega COM-i kaudu, nii et see erineb veidi Exceli faili andmetega töötamisest. Eeldusena tuleb täidetavasse keskkonda installida Excel, kuid paljud Exceli funktsioonid on saadaval programmi poolelt.

Microsoft.Office.Interop.Excel Kui kasutate programmi, arvate, et programm kirjutatakse järgmisel viisil.

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

Iga kord on tülikas ressursse vabastada, kuid kuna saate ettevalmistatud klasse kasutada, saate Exceli töötlemist suhteliselt intuitiivselt teha.

Puuduseks on aga see, et programmi viidatud teegi versioon peab vastama või ühilduma Exceli versiooniga, mis on installitud keskkonda, kus see töötab. Näiteks Exceli siseversioonile 15.0 (2013) viitamisel loodud programm saab käivituda ainult siis, kui Excel 2013 on installitud. Kui soovite, et teie programm töötaks paljudes keskkondades, peate võib-olla oma Exceli installi ühtses versioonis töös hoidma.

Kui selline toiming on võimalik, on see hea, kuid kui Exceli installitud versioon on erinev, ei saa seda majutada. Seetõttu on vaja teha midagi programmi poolel.

Teekide dünaamiline viitamine dünaamiliselt, selle asemel, et neile otse viidata

Sellisel juhul ilmneb probleem seetõttu, et teegi versioonile viidatakse programmi loomisel parandatud. See tähendab, et selle asemel, et määrata versioon programmi loomise ajal, on vaja kindlaks määrata versioon programmi täitmise ajal.

Selleks on mitmeid viise, kuid seekord lahendame selle "" "" ja "" abil.Type.GetTypeFromProgIDActivator.CreateInstancedynamic

Tavaliselt on C#-s vaja määrata tüübiteave programmi loomise ajal, kuid kui tüüp on dynamic , saab tüübi määrata täitmise ajal. object Erinevalt tüüpidest dynamic , kui muutujale seatud eksemplar on klass, saate helistada ka selle klassi meetoditele ja omadustele. Kuna aga muutujasse minev määratakse täitmise ajal, ilmneb täitmise ajal viga, kui määratud meetodit pole.

Nende abil loodud kood on järgmine.

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

Muutuja deklaratsiooni tüüp on , ja Excel.Application selle loomine on dynamic veidi erinev, kuid ülejäänud koodi kasutatakse peaaegu uuesti.

Kuna ülaltoodud kood ei viita Exceli teegile, ei ole võimalik kasutada Exceliga seotud klassi sihtteavet. Seetõttu on muutuja tüüp kõik dynamic . Samuti, kuna me ei saa klassile otse viidata, saame selle asemel Type.GetTypeFromProgID Excel.Application teabe Activator.CreateInstance Tüüp sisse ja edastame selle,Excel.Application et luua Excel.Application eksemplar . Muide, keskkonnas, kus Excelit pole installitud, ei saa te seda sisse Type saada , seega on võimalik eraldada, Type.GetTypeFromProgID kas see on installitud või mitte.

dynamic Kasutamise puuduseks on see, et klassi ei saa programmi ehitamisel kindlaks määrata. Intellisense, mis on koodi sisestamisel lõpetamisfunktsioon, ei kuva meetodite nimesid ega atribuutide nimesid. Võib olla vähem tülikas kirjutada kood alguses raamatukogule viidates ja asendada see hilisemaga dynamic .

Microsoft 365 keskkonnas töötades saate kinnitada, et see kajastub järgmiselt.

Järgmine on Office 2007 palju vanema versiooni käitamise tulemus. Kui te ei kasuta funktsiooni, mis töötab ainult kindlas versioonis, saate selle üsna laialdaselt tööle panna.

Muide, kui käivitate selle keskkonnas, kus Excelit pole installitud, saate õigesti kindlaks teha, et seda ei saa töödelda.