Excelin käyttäminen .NET:ssä asennetusta Excel-versiosta riippumatta

Sivu päivitetty :
Sivun luontipäivämäärä :

Toimintaympäristö

Visuaalinen studio
  • Visuaalinen studio 2022
.VERKKO
  • .NET 6.0
Windows
  • Windows 7
  • Windows 11
Erottua
  • Microsoft 365
  • Office 2007

Edellytykset

Windows
  • Yksi versioista
Erottua
  • Yksi versioista

Excelin kanssa toimivien kirjastojen ongelmat

Yksi tapa olla ohjelmallisesti vuorovaikutuksessa Excelin kanssa on Microsoft.Office.Interop.Excel viitata . Tämä on samanlainen kuin työskentely suoraan Excel-sovelluksen kanssa COM: n kautta, joten se eroaa hieman Excel-tiedoston tietojen käsittelystä. Lähtökohtana on, että Excel on asennettava suoritettavaan ympäristöön, mutta monet Excelin toiminnot ovat käytettävissä ohjelman puolelta.

Microsoft.Office.Interop.Excel Jos käytät ohjelmaa, luulet, että ohjelma kirjoitetaan seuraavalla tavalla.

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

On hankalaa joutua vapauttamaan resursseja joka kerta, mutta koska voit käyttää valmisteltuja luokkia, voit suorittaa Excel-käsittelyn suhteellisen intuitiivisesti.

Haittapuolena on kuitenkin se, että ohjelman viittaaman kirjaston version on vastattava tai oltava yhteensopiva Excel-version kanssa, joka on asennettu ympäristöön, jossa se toimii. Esimerkiksi ohjelma, joka on luotu viittaamalla Excelin sisäiseen versioon 15.0 (2013) kirjastoon, voidaan suorittaa vain, kun Excel 2013 on asennettu. Jos haluat, että ohjelma toimii useissa ympäristöissä, sinun on ehkä pidettävä Excel-asennus käynnissä yhtenäisessä versiossa.

Jos tällainen toimenpide on mahdollista, se on hieno, mutta jos Excelin asennettu versio on erilainen, sitä ei voida mukauttaa. Siksi on tarpeen tehdä jotain ohjelman puolella.

Kirjastoihin viittaaminen dynaamisesti sen sijaan, että niihin viitattaisiin suoraan

Tässä tapauksessa ongelma ilmenee, koska kirjastoversioon viitataan korjattuna, kun ohjelma luodaan. Tämä tarkoittaa, että sen sijaan, että määritettäisiin versio ohjelman luomisen yhteydessä, on tarpeen määrittää versio ohjelman suorittamisen yhteydessä.

On olemassa useita tapoja tehdä se, mutta tällä kertaa ratkaisemme sen käyttämällä "" "" ja "Type.GetTypeFromProgIDActivator.CreateInstance".dynamic

Normaalisti C #: ssa on tarpeen määrittää tyyppitiedot ohjelman luomisen yhteydessä, mutta jos tyyppi on dynamic , tyyppi voidaan määrittää suoritushetkellä. object Toisin kuin dynamic tyypit, jos muuttujaksi määritetty esiintymä on luokka, voit myös kutsua kyseisen luokan menetelmiä ja ominaisuuksia. Koska muuttujaan menevä määritetään suorituksen ajoituksessa, suoritushetkellä tapahtuu virhe, jos määritettyä menetelmää ei ole.

Näiden avulla luotu koodi on seuraava.

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

Muuttujan ilmoituksen tyyppi on , ja Excel.Application sen luominen on dynamic hieman erilainen, mutta loput koodista käytetään lähes uudelleen.

Koska yllä oleva koodi ei viittaa Excel-kirjastoon, Exceliin liittyviä luokkatietoja ei voi käyttää. Siksi muuttujan tyyppi on kaikki dynamic . Koska emme voi viitata luokkaan suoraan,Excel.Application saamme sen sijaan Excel.Application Type.GetTypeFromProgID Tyyppitiedot Activator.CreateInstance sisään ja välitämme ne luodaksemme Excel.Application esiintymän . Muuten, ympäristössä, jossa Exceliä ei ole asennettu, et voi saada sitä sisään Type , joten on mahdollista eristää, Type.GetTypeFromProgID onko se asennettu vai ei.

dynamic Käytön haittana on, että luokkaa ei voida määrittää ohjelmaa rakennettaessa. Intellisense, joka on täydennystoiminto koodia syötettäessä, ei näytä menetelmien ja ominaisuuksien nimiä. Voi olla vähemmän hankalaa kirjoittaa koodia viittaamalla kirjastoon alussa ja korvata se myöhemmällä dynamic .

Kun suoritat Microsoft 365 -ympäristössä, voit varmistaa, että se näkyy seuraavasti.

Seuraavassa on tulos, että se on suoritettu paljon vanhemmassa Office 2007 -versiossa. Jos et käytä toimintoa, joka toimii vain tietyssä versiossa, voit saada sen toimimaan melko laajasti.

Muuten, jos suoritat sen ympäristössä, jossa Exceliä ei ole asennettu, voit määrittää oikein, että sitä ei voi käsitellä.