NET-alapú Excel használata az Excel telepített verziójától függetlenül

Oldal frissítve :
Oldal létrehozásának dátuma :

Működési környezet

Visual Studio
  • Visual Studio 2022
.HÁLÓ
  • .NET 6.0
Windows
  • Windows 7 esetén
  • Windows 11 esetén
Kitűnik
  • Microsoft 365 esetén
  • Office 2007 esetén

Előfeltételek

Windows
  • Az egyik változat
Kitűnik
  • Az egyik változat

Az Excellel működő tárakkal kapcsolatos problémák

Az Excellel való programozott interakció egyik módja a Microsoft.Office.Interop.Excel hivatkozás. Ez hasonló az Excel alkalmazással való közvetlen munkához a COM-on keresztül, így kissé eltér az Excel-fájlban lévő adatokkal végzett munkától. Előfeltételként az Excelt telepíteni kell a végrehajtandó környezetbe, de az Excel számos funkciója elérhető a program oldaláról.

Microsoft.Office.Interop.Excel Ha a programot használja, úgy gondolja, hogy a program a következő módon lesz írva.

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

Nehézkes, hogy minden alkalommal erőforrásokat kell felszabadítania, de mivel használhatja az előkészített osztályokat, viszonylag intuitív módon végezheti el az Excel feldolgozását.

A hátránya azonban az, hogy a program által hivatkozott könyvtár verziójának meg kell egyeznie vagy kompatibilisnek kell lennie az Excel verziójával, amely abban a környezetben van telepítve, amelyben fut. Az Excel belső verziójú 15.0-s (2013-as) kódtárára hivatkozva létrehozott program például csak akkor futtatható, ha az Excel 2013 telepítve van. Ha azt szeretné, hogy a program több környezetben is fusson, előfordulhat, hogy az Excel-telepítést konzisztens verzión kell futtatnia.

Ha ilyen művelet lehetséges, akkor rendben van, de ha az Excel telepített verziója más, akkor nem helyezhető el. Ezért valamit tenni kell a program oldalán.

Könyvtárakra való dinamikus hivatkozás dinamikus hivatkozással a közvetlen hivatkozás helyett

A probléma ebben az esetben azért fordul elő, mert a program létrehozásakor a könyvtár verziójára hivatkoznak. Ez azt jelenti, hogy a program létrehozásakor a verzió meghatározása helyett a program végrehajtásakor meg kell határozni a verziót.

Ennek számos módja van, de ezúttal a "" "" és ""Type.GetTypeFromProgIDActivator.CreateInstance használatával oldjuk meg.dynamic

Általában a C# nyelvben a típusinformációt a program létrehozásakor kell meghatározni, de ha a típus , akkor a típus dynamic a végrehajtáskor határozható meg. object A típusokkal ellentétben dynamic , ha a változóra beállított példány egy osztály, akkor az adott osztály metódusait és tulajdonságait is meghívhatja. Mivel azonban a változóba kerülés a végrehajtás időzítésénél kerül meghatározásra, hiba lép fel a végrehajtás időpontjában, ha nincs meghatározott módszer.

Az ezekkel létrehozott kód a következő.

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

A változó dynamic deklarációjának típusa , és Excel.Application a létrehozása kissé eltérő, de a kód többi része szinte újra felhasználásra kerül.

Mivel a fenti kód nem hivatkozik az Excel-kódtárra, nem lehet használni a cél Excel-hez kapcsolódó osztályinformációkat. Ezért a változó típusa mind dynamic . Továbbá, mivel nem hivatkozhatunk közvetlenül az osztályra, ehelyett Excel.Application Type.GetTypeFromProgID lekérjük a Type információtActivator.CreateInstance, és átadjuk neki,Excel.Application hogy létrehozzuk Excel.Application a példányát. By the way, olyan környezetben, ahol az Excel nincs telepítve, nem kaphatja meg Type , így elkülöníthető, Type.GetTypeFromProgID hogy telepítve van-e vagy sem.

dynamic A használat hátránya, hogy az osztály nem határozható meg a program létrehozásakor. Az Intellisense, amely egy befejező függvény a kód bevitelekor, nem jeleníti meg a metódusneveket és a tulajdonságneveket. Lehet, hogy kevésbé nehézkes kódot írni a könyvtárra hivatkozva az elején, dynamic és később lecserélni.

Ha Microsoft 365 környezetben fut, ellenőrizheti, hogy az alábbiak szerint jelenik meg.

Az alábbiakban az Office 2007 sokkal régebbi verzióján való futtatás eredménye. Ha nem használ olyan funkciót, amely csak egy adott verzióban működik, akkor meglehetősen széles körben működhet.

Egyébként, ha olyan környezetben futtatja, ahol az Excel nincs telepítve, helyesen megállapíthatja, hogy nem lehet feldolgozni.