Delo z Excelom v ogrodju .NET neodvisno od nameščene različice Excela

Stran posodobljena :
Datum ustvarjanja strani :

Delovno okolje

Visual Studio
  • Visual Studio 2022
.MREŽA
  • .NET 6.0
Windows
  • Windows 7
  • Windows 11
Excel
  • Microsoft 365
  • Office 2007

Predpogoji

Windows
  • Ena od različic
Excel
  • Ena od različic

Težave s knjižnicami, ki delujejo z Excelom

Eden od načinov za programsko interakcijo z Excelom je Microsoft.Office.Interop.Excel sklicevanje . To je podobno delu neposredno z aplikacijo Excel prek COM, zato se nekoliko razlikuje od dela s podatki v datoteki Excel. Kot prostor mora biti Excel nameščen v okolju, ki ga je treba izvesti, vendar so številne funkcije Excela na voljo na programski strani.

Microsoft.Office.Interop.Excel Če uporabljate program, boste mislili, da bo program napisan na naslednji način.

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

Težko je vsakič sprostiti vire, a ker lahko pripravljene razrede uporabite, lahko obdelavo Excela izvedete relativno intuitivno.

Pomanjkljivost pa je, da se mora različica knjižnice, na katero se sklicuje program, ujemati ali biti združljiva z različico Excela, nameščeno v okolju, v katerem se izvaja. Program, ustvarjen s sklicevanjem na knjižnico programa Excel notranje različice 15.0 (2013), se lahko na primer zažene le, ko je nameščen Excel 2013. Če želite, da se program izvaja v številnih okoljih, boste morda morali ohraniti Excelovo namestitev v dosledni različici.

Če je takšna operacija mogoča, je v redu, če pa je nameščena različica Excela drugačna, je ni mogoče sprejeti. Zato je treba nekaj storiti na programski strani.

Dinamično sklicevanje na knjižnice z dinamičnim sklicevanjem, namesto da bi se nanje neposredno sklicevali

Do težave v tem primeru pride, ker je sklic na različico knjižnice nespremenljiv, ko je program ustvarjen. To pomeni, da je namesto določanja različice v času ustvarjanja programa potrebno določiti različico v času izvajanja programa.

Obstaja več načinov za to, vendar ga bomo tokrat rešili z uporabo "" "" in "Type.GetTypeFromProgIDActivator.CreateInstance".dynamic

Običajno je v C # treba določiti informacije o vrsti v času ustvarjanja programa, če pa je dynamic vrsta , se lahko tip določi v času izvedbe. object Če je primerek, nastavljen na spremenljivko, za razliko od dynamic vrst razred, lahko pokličete tudi metode in lastnosti tega razreda. Ker pa se tisto, kar gre v spremenljivko, določi v času izvršitve, se bo v času izvršitve pojavila napaka, če ni določene metode.

Koda, ustvarjena z njimi, je naslednja.

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

Vrsta deklaracije spremenljivke je , ustvarjanje pa je dynamic nekoliko drugačno, Excel.Application preostanek kode pa se skoraj ponovno uporabi.

Ker se zgornja koda ne nanaša na Excelovo knjižnico, ni mogoče uporabiti ciljnih informacij o razredu, povezanih z Excelom. Zato je vrsta spremenljivke vse dynamic . Ker se ne moremo neposredno sklicevati na razred, namesto tega Excel.Application Type.GetTypeFromProgID dobimo podatke Activator.CreateInstance o vrsti in jih posredujemo,Excel.Application da ustvarimo Excel.Application primerek . Mimogrede, v okolju, kjer Excel ni nameščen, ga ne morete dobiti v Type , zato je mogoče izolirati, Type.GetTypeFromProgID ali je nameščen ali ne.

dynamic Pomanjkljivost uporabe je, da razreda ni mogoče določiti pri gradnji programa. Intellisense, ki je funkcija dokončanja pri vnosu kode, ne prikazuje imen metod in imen lastnosti. Morda je manj okorno napisati kodo s sklicevanjem na knjižnico na začetku in jo zamenjati s dynamic kasneje.

Ko se izvaja v okolju Microsoft 365, lahko potrdite, da se odraža na naslednji način.

V nadaljevanju je prikazan zagon v veliko starejši različici sistema Office 2007. Če ne uporabljate funkcije, ki deluje samo v določeni različici, lahko poskrbite, da deluje precej široko.

Mimogrede, če ga zaženete v okolju, kjer Excel ni nameščen, lahko pravilno ugotovite, da ga ni mogoče obdelati.