Dirbkite su "Excel" .NET nepriklausomai nuo įdiegtos "Excel" versijos

Puslapis atnaujintas :
Puslapio sukūrimo data :

Darbo aplinka

Vizualinė studija
  • "Visual Studio 2022"
.GRYNOJI
  • .NET 6.0
Windows
  • Langai 7
  • Langai 11
Excel
  • "Microsoft 365"
  • "Office 2007"

Būtinosios sąlygos

Windows
  • Viena iš versijų
Excel
  • Viena iš versijų

Problemos, susijusios su bibliotekomis, kurios veikia su "Excel"

Vienas iš būdų programiškai sąveikauti su "Excel" yra Microsoft.Office.Interop.Excel nuoroda . Tai panašu į darbą tiesiogiai su "Excel" programa per COM, todėl jis šiek tiek skiriasi nuo darbo su "Excel" failo duomenimis. Kaip prielaida, "Excel" turi būti įdiegta aplinkoje, kurią reikia vykdyti, tačiau daugelis "Excel" funkcijų yra prieinamos iš programos pusės.

Microsoft.Office.Interop.Excel Jei naudojate programą, manote, kad programa bus parašyta taip.

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

Sunku kiekvieną kartą išleisti išteklius, tačiau kadangi galite naudoti paruoštas klases, "Excel" apdorojimą galite atlikti gana intuityviai.

Tačiau trūkumas yra tas, kad programos nurodyta bibliotekos versija turi atitikti arba būti suderinama su "Excel" versija, įdiegta aplinkoje, kurioje ji veikia. Pavyzdžiui, programa, sukurta nurodant vidinę "Excel" 15.0 (2013) versiją, gali veikti tik įdiegus "Excel 2013". Jei norite, kad programa veiktų daugelyje aplinkų, gali reikėti, kad "Excel" diegimas veiktų nuoseklia versija.

Jei tokia operacija yra įmanoma, tai gerai, bet jei įdiegta "Excel" versija skiriasi, ji negali būti pritaikyta. Todėl būtina kažką daryti programos pusėje.

Bibliotekų nuorodos dinamiškai naudojant dinamines, o ne tiesiogiai jas nurodant

Šiuo atveju problema kyla dėl to, kad bibliotekos versija yra nurodyta fiksuota, kai programa yra sukurta. Tai reiškia, kad vietoj to, kad būtų nustatyta versija programos kūrimo metu, būtina nustatyti versiją programos vykdymo metu.

Yra keletas būdų, kaip tai padaryti, tačiau šį kartą mes tai išspręsime naudodami "" "" ir "Type.GetTypeFromProgIDActivator.CreateInstance".dynamic

Paprastai C#, reikia nustatyti tipo informaciją programos kūrimo metu, tačiau jei tipas yra dynamic , tipą galima nustatyti vykdymo metu. object Skirtingai nuo dynamic tipų, jei kintamasis nustatytas egzempliorius yra klasė, taip pat galite skambinti tos klasės metodais ir savybėmis. Tačiau, kadangi tai, kas patenka į kintamąjį, nustatoma vykdymo metu, vykdymo metu įvyks klaida, jei nėra nurodyto metodo.

Kodas, sukurtas naudojant juos, yra toks.

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

Kintamojo deklaravimo tipas yra dynamic , o Excel.Application sukūrimas šiek tiek skiriasi, tačiau likusi kodo dalis beveik pakartotinai naudojama.

Kadangi aukščiau pateiktas kodas nenurodo "Excel" bibliotekos, neįmanoma naudoti tikslinės su "Excel" susijusios klasės informacijos. Todėl kintamojo tipas yra visas dynamic . Be to, kadangi negalime tiesiogiai nurodyti klasės,Excel.Application vietoj to Excel.Application Type.GetTypeFromProgID gauname informaciją Tipas Activator.CreateInstance ir perduodame ją, kad sukurtume Excel.Application egzempliorių . Beje, aplinkoje, kurioje "Excel" nėra įdiegta, negalite jos gauti Type , todėl galima atskirti, ar ji įdiegta, Type.GetTypeFromProgID ar ne.

dynamic Naudojimo trūkumas yra tas, kad klasės negalima nustatyti kuriant programą. "Intellisense", kuri yra užbaigimo funkcija įvedant kodą, nerodo metodų pavadinimų ir ypatybių pavadinimų. Gali būti ne taip sudėtinga pradžioje parašyti kodą su nuoroda į biblioteką ir vėliau jį dynamic pakeisti.

Kai veikiate "Microsoft 365" aplinkoje, galite patvirtinti, kad ji rodoma taip, kaip nurodyta toliau.

Toliau pateikiamas jo paleidimo daug senesnėje "Office 2007" versijoje rezultatas. Jei nenaudojate funkcijos, kuri veikia tik konkrečioje versijoje, galite padaryti, kad ji veiktų gana plačiai.

Beje, jei paleisite jį aplinkoje, kurioje nėra įdiegta "Excel", galite teisingai nustatyti, kad jos negalima apdoroti.